1778D Flexible String Revisit
1778D Flexible String Revisit
题目大意:
给你两个长度均为 n n n二进制数列: S , T S,T S,T 每次可以把 S S S中的一位取反,问你 S → T S \to T S→T的期望方案数。
做法:
dp
我们考虑 d p i dp_i dpi表示 i i i个不一样的位置 → i − 1 \to i - 1 →i−1个不一样的位置的期望方案数
每次有
i
n
\dfrac{i}{n}
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
=
1
+
n
−
i
n
∗
(
f
i
+
1
+
f
i
)
f_i = 1 + \dfrac{n - i}{n} * (f_{i + 1} + f_i)
fi=1+nn−i∗(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个字符需要匹配,那么
a
n
s
=
∑
i
=
1
x
ans = \sum_{i = 1}^{x}
ans=∑i=1x
code
#include<bits/stdc++.h>
using namespace std;
const long long mod = 998244353;
const int N = 1e6 + 5;
int n;
char s[N] , t[N];
long long fac[N + 5] , inv[N + 5] , ans , f[N] , p;
long long ksm (long long x , long long y) {
if(!y)
return 1;
long long z = ksm (x , y / 2);
z = z * z % mod;
if (y & 1)
z = z * x % mod;
return z;
}
void pre () {
fac[0] = 1;
for (int i = 1 ; i <= N ; i ++) {
fac[i] = fac[i - 1] * i % mod;
}
inv[N] = ksm(fac[N] , mod - 2);
for (int i = N - 1 ; i >= 0 ; i --) {
inv[i] = inv[i + 1] * (i + 1) % mod;
}
}
int main () {
int T , dif;
pre ();
scanf ("%d" , &T);
while(T --) {
scanf ("%d" , &n);
scanf("%s%s",s+1,t+1);
dif = 0;
for (int i = 1 ; i <= n ; i++) {
if (s[i] != t[i]) {
dif ++;
}
}
inv[n] = ksm(n , mod - 2);
f[n] = 1;
for (int i = n - 1 ; i >= 1 ; i--) {
f[i] = (n + (n - i) * f[i + 1] % mod) * ksm (i , mod - 2) % mod;
}
ans = 0;
for (int i = 1 ; i <= dif ; i++) {
ans = (ans + f[i]) % mod;
}
printf("%lld\n" , ans);
}
return 0;
}