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 ST的期望方案数。

做法:

dp

我们考虑 d p i dp_i dpi表示 i i i个不一样的位置 → i − 1 \to i - 1 i1个不一样的位置的期望方案数

每次有 i n \dfrac{i}{n} ni的概率翻转一个未匹配字符, n − i n \dfrac{n - i}{n} nni的概率翻转一个已匹配字符。翻转到已匹配字符需要 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+nni(fi+1+fi)

化简一下:
f i = n + ( n − i ) ∗ f i + 1 i f_i = \dfrac{n + (n - i) * f_{i + 1}}{i} fi=in+(ni)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;
}
posted @ 2023-03-22 20:21  2020fengziyang  阅读(2)  评论(0编辑  收藏  举报  来源