AtCoder Regular Contest 151

A

如果 \(S\)\(T\) 的某一位相同,那么 \(U\) 无论怎么填都无法影响答案,为了字典序最小,一定填 \(0\)
只考虑 \(S\)\(T\) 不同的位置,假设有 \(k\) 位不同,易知 \(k\) 为奇数一定无解。
如果 \(k\) 为偶数,那么 \(U\) 数组可以视为在 \(S\) 数组上修改了 \(k/2\) 位。考虑如何修改才能让字典序最小。
一定是把 \(S\) 前面的 \(1\) 都换成 \(0\)。当然,如果 \(k/2\) 次用不完,还得被迫把后面的一些 \(0\) 改成 \(1\)
讲的比较抽象,具体看代码。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,s[N],t[N],ans[N];
signed main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		char ch;cin>>ch;
		s[i]=ch-'0';
	}
	for(int i=1;i<=n;++i)
	{
		char ch;cin>>ch;
		t[i]=ch-'0';
	}
	int cnt=0;
	for(int i=1;i<=n;++i)
		if(s[i]!=t[i])cnt++;
	if(cnt%2==1)cout<<-1<<endl;
	else
	{
		int cur=0;
		for(int i=1;i<=n;++i)
		{
			if(s[i]==t[i])ans[i]=0;
			else //不同的地方 
			{
				if(s[i]==1)
				{
					if(cur<cnt/2)ans[i]=0,cur++;
					else ans[i]=1;
				}
				else ans[i]=0;
			}
		}
		int res=cnt/2-cur;
		if(res>0)
		{
			for(int i=n;i>=1;--i)
			{
				if(s[i]!=t[i])
				{
					if(s[i]==0&&ans[i]==0)
					{
						ans[i]=1;res--;
						if(res==0)break;
					}
				}	
			} 
		}
		for(int i=1;i<=n;++i)cout<<ans[i];
	}
	return 0;
}

B

Description

给定一个 \(1\sim N\) 的排列 \(P\),找到符合以下条件的 \(A\) 数组的数量 \(\bmod 998244353\)

  • 对于 \(1\sim N\) 的每一个 \(i\)\(1\le A_i\le M\)
  • \(A\) 数组字典序小于 \((A_{P_1},A_{P_2},\cdots,A_{P_n})\) 数组。

Solution

考虑到一共有 \(M^N\)\(A\) 序列,直接计算合法方案数比较复杂,我们需要进行一下转化。

不难发现有一个 \(A<AP\) 的方案就一定对应一个 \(A>AP\) 的方案(对称性),所以问题可以转化为求 \(A=AP\) 的方案数 \(X\),答案即为 \(\dfrac{M^N-X}{2}\)

那么如何计算 \(A=AP\) 的方案数 \(X\) 呢?

考虑到如果 \(A=AP\),那么 \(A_i\)\(A_{P_i}\) 一定相等,所以可以在 \(i\)\(P_i\) 之间连一条边,问题就转化成了求图中连通块的个数。若连通块的个数为 \(C\),那么 \(X=M^C\),问题的答案就变为了 \(\dfrac{M^N-M^C}{2}\)

Tips:

  • \(\bmod\) 意义下不能直接除 \(2\),需要乘 \(2\) 的逆元。

Code

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
const int mod=998244353;
int n,m,p[N],vis[N],inv2=499122177;//2的逆元 
vector<int>g[N];
int Qpow(int x,int power)//快速幂 
{
	int res=1;
	for(;power;power>>=1,x=x*x%mod)
		if(power&1)res=res*x%mod;
	return res;
}
void dfs(int u)//求连通块数量 
{
	if(vis[u])return;vis[u]=1;
	for(int i=0;i<g[u].size();++i)
		dfs(g[u][i]);
}
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i)
	{
		cin>>p[i];
		g[i].push_back(p[i]);//建边 
	}
	int c=0;
	for(int i=1;i<=n;++i)
		if(!vis[i])dfs(i),c++;
	cout<<(Qpow(m,n)-Qpow(m,c)+mod)*inv2%mod;
	return 0;
}
posted @ 2022-10-17 22:16  lnwhl  阅读(52)  评论(1编辑  收藏  举报