Codeforces #349 div1 C. Codeword 组合数学 递推

题解

首先需要看出方案数只和模式串的长度有关,和具体的字符无关。

由于模式串的长度和规模为105105,则不同长度模式串最多有105105种,因而如果如果我们若能在线性时间内推出某长度下的结果,复杂就会变成Θ(nn)Θ(nn)

具体记数的过程比较复杂,需要考虑枚举模式串为第一次匹配的情况。

SS为主串,模式串为PPaiai|S|=i|S|=i时的方案数。

ai={026ai1+(n1i1)25i|P| if i<|P| if i|P|ai={0 if i<|P|26ai−1+(n−1i−1)⋅25i−|P| if i⩾|P|

26ai126ai−1包含了第一次匹配在S1Si1S1⋯Si−1出现的情况,最后一个位置放啥都行。

(n1i1)25i|P|(n−1i−1)⋅25i−|P| 是在SiSi才出现第一次匹配的情况。S1Si1S1⋯Si−1能匹配PiP|P|1Pi⋯P|P|−1Si=P|P|Si=P|P|。最后一位确定,然后在S1Si1S1⋯Si−1选择PiP|P|1Pi⋯P|P|−1的匹配,即(n1i1)(n−1i−1),剩余的位置每个位置都含有2525种可能,因为不能是它之后第一个确定的位置的字符。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
// head
const int N = 1e5+5;
const int MOD = 1e9+7;

LL powmod(LL a, LL b) {
    LL ans = 1;
    for (; b; b >>= 1) {
        if (b & 1) ans = (a * ans) % MOD;
        a = a * a % MOD;
    }
    return ans;
}

int fac[N], inv[N], p25[N];

void init() {
    inv[0] = fac[0] = p25[0] = 1;
    for (int i = 1; i < N; i++) {
        fac[i] = (LL)fac[i-1] * i % MOD;
        inv[i] = powmod(fac[i], MOD-2);
        p25[i] = (LL)p25[i-1] * 25 % MOD;
    }
}

LL C(int n, int m) {
    return (LL)fac[n] * inv[m] % MOD * inv[n-m] % MOD;
}

int a[N], ans[N];
vector<PII> query[N];

void solve(int n) {
    a[n] = 1;
    for (int i = 0; i < n; i++) {
        a[i] = 0;
    }
    for (int i = n+1; i < N; i++) {
        a[i] = (LL)a[i-1] * 26 % MOD;
        a[i] = (a[i] + C(i-1, n-1) * p25[i-n]) % MOD;
    }
    for (auto q : query[n]) {
        ans[q.fi] = a[q.se];
    }
}

char s[N];

int main() {
    init();
    int n, cur, q, x, cnt = 0;
    scanf("%d", &n);
    scanf("%s", s);
    cur = strlen(s);
    for (int i = 0; i < n; i++) {
        scanf("%d", &q);
        if (q == 1) {
            scanf("%s", s);
            cur = strlen(s);
        } else {
            scanf("%d", &x);
            query[cur].push_back(make_pair(cnt++, x));
        }
    }
    for (int i = 0; i < N; i++) {
        if (query[i].size() == 0) continue;
        solve(i);
    }
    for (int i = 0; i < cnt; i++) {
        printf("%d\n", ans[i]);
    }
    return 0;
}



阅读更多
个人分类: dp
上一篇CodeForces 659G Fence Divercity (DP)
下一篇CF 668C(Little Artem and Random Variable-概率)
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭