8.15 模拟赛小结

发布时间 2023-08-15 20:49:28作者: g1ove

前言

最自闭的一集

T1 这一切

题意:给你一个图,定义操作为 若一个点只有一条白边 那么剩余的白边就会自动变黑 求至少要提前染几条边 通过若干次操作后使所有边都变黑

思考:画一下图就知道 满足所有点只有一条出边 其实就是一棵树 所以将每个联通快多余的边删掉即可

Code

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,m,ans;
int head[N],tot=1;
struct edge{
	int to,next;
}e[N*4];
void add(int u,int v)
{
	e[tot]=(edge){v,head[u]};
	head[u]=tot++;
}
int vis[N],cnt,p;
void dfs(int now)
{
	p++;
	vis[now]=1;
	for(int i=head[now];i;i=e[i].next)
	{
		int to=e[i].to;
		cnt++;
		if(!vis[to]) dfs(to);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=n;i++)
		if(!vis[i]) cnt=0,p=0,dfs(i),ans+=cnt/2-p+1;
	cout<<ans;
	return 0;
}

T2 都是 原题

题意:你可以随意交换数列两个数 使得最后的数列成为单峰数列 即存在一个 \(a_x\) 满足:

  • \(i<k\) \(a_i>a_{i-1}\)
  • \(i<k\) \(a_i<a_{i-1}\)

e.g 1 1 4 5 4 1
考场上是问了同学的 一开始一直在想逆序对
其实不妨这样思考:
\(1\) 开始考虑 \(1\) 必须扔到最前面或者最后面 扔完就变成了一个子问题
这样一想这问题就变成一个弟弟题了
所以往前找到有几个数和往后找到有几个数 哪里少就往哪里扔就行
树状数组维护即可

Code

#include<bits/stdc++.h>
#define ll long long
#define N 300005
using namespace std;
int n,a[N];
ll ans;
vector <int> pos[N];
struct tree{
	ll tr[N];
	void add(int x,int v)
	{
		while(x<=n)
		{
			tr[x]+=v;
			x+=x&-x; 
		}
	}
	ll ask(int x)
	{
		ll sum=0;
		while(x)
		{
			sum+=tr[x];
			x-=x&-x;
		}
		return sum;
	}
}tr;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		pos[x].push_back(i);
		tr.add(i,1);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<pos[i].size();j++) tr.add(pos[i][j],-1);
		for(int j=0;j<pos[i].size();j++)
		{
			int x=pos[i][j];
			ans+=min(tr.ask(x-1),tr.ask(n)-tr.ask(x));
		}
	}
	cout<<ans;
	return 0;
}

T3

呜呜呜我好菜写了一天
题意:有 \(n\) 个笼子 每个笼子可能会有动物 \(A,B,C\) \(A\) 能吃 \(B\),\(B\) 能吃 \(C\),\(C\) 能吃 \(A\).明显最初有 \(3^n\) 种状态
image
我好菜 不会在线算法 被吊打了
想想在线怎么做
考虑两个并查集 \(u,v\) 要合并到 \(u\)
那么 \(u\) 子树所有胜利状态应该乘上 \(\frac{2}{3}\) \(v\) 子树所有节点胜利状态应该乘上 \(\frac{1}{3}\) 这是题目给定的胜利概率 然后两棵树再并起来

然后因为并查集动态搞我太菜了不会 所以只能离线把原树拍到树上 dfs 序解决
时间复杂度还带个 \(log\) 我太菜了

#include<bits/stdc++.h>
#define ll long long
#define N 400005
using namespace std;
ll mod=998244353,inv[5],pw=1;
int n,m;
int trs[N][2],fa[N],cnt,pre[N];
struct prob{
	int opr,u,v;
}op[N];
int in[N],out[N],dfn;
void dfs(int now)
{
	if(!now) return;
	in[now]=++dfn;
	dfs(trs[now][0]);
	dfs(trs[now][1]);
	out[now]=dfn;
}
int tr[N];
void add(int x,ll v)
{
	while(x<=dfn)
	{
		tr[x]=tr[x]*v%mod;
		x+=x&-x;
	}
}
ll ask(int x)
{
	ll sum=1;
	while(x)
	{
		sum=tr[x]*sum%mod;
		x-=x&-x;
	}
	return sum;
}
int main()
{
	inv[2]=(mod-mod/2);
	inv[3]=(mod-mod/3)*inv[2]%mod;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		pre[i]=i,pw=pw*3%mod;
	cnt=n;
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&op[i].opr);
		if(op[i].opr==1)
		{
			scanf("%d%d",&op[i].u,&op[i].v);
			int node=++cnt;
			fa[pre[op[i].u]]=node,fa[pre[op[i].v]]=node;
			trs[node][0]=pre[op[i].u],trs[node][1]=pre[op[i].v];
			pre[op[i].u]=node;
		}
		else
			scanf("%d",&op[i].u);
	}
	for(int i=1;i<=cnt;i++)
	{
		if(fa[i]==0) dfs(i);
	}
	for(int i=1;i<=n;i++)
		pre[i]=i;
	for(int i=1;i<=dfn;i++)
		tr[i]=1;
	add(1,pw);
	for(int i=1;i<=m;i++)
	{
		if(op[i].opr==1)
		{	
			int u=pre[op[i].u],v=pre[op[i].v];
			add(in[u],inv[3]*2ll%mod),add(out[u]+1,3ll*inv[2]%mod);
			add(in[v],inv[3]),add(out[v]+1,3);
			pre[op[i].u]=fa[u];
		}
		else
			printf("%lld\n",ask(in[op[i].u]));
	}
	return 0;
}