题解
首先需要看出方案数只和模式串的长度有关,和具体的字符无关。
由于模式串的长度和规模为 105 ,则不同长度模式串最多有 105−−−√ 种,因而如果如果我们若能在线性时间内推出某长度下的结果,复杂就会变成 Θ(nn−−√) 。
具体记数的过程比较复杂,需要考虑枚举模式串为第一次匹配的情况。
若 S 为主串,模式串为 P , ai 为 |S|=i 时的方案数。
ai={026ai−1+(n−1i−1)⋅25i−|P| if i<|P| if i⩾|P|
26ai−1 包含了第一次匹配在 S1⋯Si−1 出现的情况,最后一个位置放啥都行。
(n−1i−1)⋅25i−|P| 是在 Si 才出现第一次匹配的情况。 S1⋯Si−1 能匹配 Pi⋯P|P|−1 且 Si=P|P| 。最后一位确定,然后在 S1⋯Si−1 选择 Pi⋯P|P|−1 的匹配,即 (n−1i−1) ,剩余的位置每个位置都含有 25 种可能,因为不能是它之后第一个确定的位置的字符。
#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; }