CF1778D Flexible String Revisit
题目大意
给出两个长度均为 n n n的01序列 S S S和 T T T,每次随机将 S S S中的某一位取反,求第一次 S = T S=T S=T时期望的操作次数。
有多组数据。
题解
因为是随机取反的,所以我们只需要知道 S S S和 T T T中相等的位的数量和不相等的位的数量。
设 f i f_i fi表示未匹配的位的数量为 i i i,翻转序列 S S S中不匹配的位置的期望操作次数。
考虑转移。每次有 i n \dfrac in ni的概率旋转一个不匹配的字符,有 n − i n \dfrac{n-i}{n} nn−i的概率翻转一个已匹配的字符。翻转已匹配的字符后需要 f i + 1 f_{i+1} fi+1的期望操作次数才能回到当前状态,然后还需要 f i f_i fi的期望操作次数才能再翻转一个未匹配字符,那么
f i = i n × 1 + n − i n × ( 1 + f i + 1 + f i ) f_i=\dfrac in\times 1+\dfrac{n-i}{n}\times (1+f_{i+1}+f_i) fi=ni×1+nn−i×(1+fi+1+fi)
化简得
f i = n + ( n − i ) f i + 1 i f_i=\dfrac{n+(n-i)f_{i+1}}{i} fi=in+(n−i)fi+1
当然, f n = 1 f_n=1 fn=1,因为在这种情况下无论怎么翻转,都会翻转一个未匹配字符。
设当前有 k k k个字符未匹配,那么答案为 f k + f k − 1 + ⋯ + f 1 f_k+f_{k-1}+\cdots+f_{1} fk+fk−1+⋯+f1。
时间复杂度为 O ( ∑ n ) O(\sum n) O(∑n)。当然,如果提前处理 f f f数组,那么时间复杂度可以达到 O ( m x n + t ) O(mxn+t) O(mxn+t),mxn表示输入中最大的 n n n。
code
#include<bits/stdc++.h>
using namespace std;
int t,n,v;
char a[1000005],b[1000005];
long long ans,f[1000005];
long long mod=998244353;
long long mi(long long t,long long v){
if(!v) return 1;
long long re=mi(t,v/2);
re=re*re%mod;
if(v&1) re=re*t%mod;
return re;
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d",&n);
scanf("%s%s",a,b);
v=0;
for(int i=0;i<=n;i++) f[i]=0;
for(int i=0;i<n;i++){
if(a[i]!=b[i]) ++v;
}
f[n]=1;
for(int i=n-1;i>=1;i--){
f[i]=(n+(n-i)*f[i+1])%mod*mi(i,mod-2)%mod;
}
ans=0;
for(int i=v;i>=1;i--){
ans=(ans+f[i])%mod;
}
printf("%lld\n",ans);
}
return 0;
}