# Codeforces 1778D Flexible String Revisit
## 給兩個長度n之字串a和b,且其都由0或1組成,定義操作為隨機挑a中一個字元,如果為1則將其變0,為0則將其變1,問操作幾步使a變為b之期望操作步數(變為b後停止操作),$n \le 10^6$。
> https://codeforces.com/contest/1778/problem/D
定義dp(i)為起始狀態a與b之字元相等個數有i個,期望操作幾步使得a等於b,然後我們很容易得到:
\begin{array}{ll}
& dp(i) = 1 + \frac{i}{n}dp(i-1) + \frac{n-i}{n}dp(i+1) \\
& dp(n) = 0 \\
& dp(0) = 1 + dp(1)
\end{array}
然後然後我就不會了==,感謝這位大老的想法又讓可憐菜雞學到一招遞推化簡技巧QQ
>https://codeforces.com/blog/entry/111780?#comment-999204
>
觀察上面第三式發現dp第0項只與dp第一項有關,考慮dp(1):
\begin{array}{ll}
& dp(1) = 1 + \frac{1}{n}dp(0) + \frac{n-1}{n}dp(2)
\end{array}
可以發現上式中dp(0)可直接拆成dp(1)與常數再化簡,則式子變為:
\begin{array}{ll}
& dp(1) = \alpha + \beta dp(2)
\end{array}
照這邏輯則dp(i)僅會跟dp(i+1)和兩個常數f(i),g(i)有關,可以得到:
\begin{array}{ll}
& dp(i) = f(i) + g(i) dp(i+1)
\end{array}
將最一開始之遞迴式之dp(i-1)代換掉比較係數可得:
\begin{array}{ll}
f(i) = \frac{n + if(i-1)}{n - ig(i-1)},\
g(i) = \frac{n - i}{n - ig(i-1)}
\end{array}
然後 就沒有然後了==
```cpp=
#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define ll long long
#define pii pair<int, int>
#define pll pair<long long, long long>
#define F first
#define S second
#define endl '\n'
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
ll qmul(ll x, ll y){
ll cur = x, ans = 1;
while(y > 0){
if(y & 1) ans = (ans * cur) % mod;
cur = (cur * cur) % mod;
y >>= 1;
}
return ans;
}
void solve(){
int n; cin >> n;
string a, b; cin >> a >> b;
int cnt = 0;
for(int i=0; i<n; i++) if(a[i] == b[i]) cnt++;
ll f[n+1], g[n+1], dp[n+1];
f[0] = g[0] = 1;
for(int i=1; i<=n-1; i++){
ll inv = (n - g[i-1] * i % mod) % mod;
if(inv < 0) inv += mod;
inv = qmul(inv, mod - 2);
f[i] = (n + f[i-1] * i) % mod * inv % mod;
g[i] = (n - i) * inv % mod;
}
dp[n] = 0;
for(int i=n-1; i>=cnt; i--){
dp[i] = f[i] + g[i] * dp[i+1];
dp[i] %= mod;
}
cout << dp[cnt] << endl;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
int t =1;
cin >> t;
while(t--)
solve();
return 0;
}
```
###### tags: `dp` `probabilities` `math`