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;
}