题目
题目链接:http://codeforces.com/problemset/problem/666/C
题目来源:Codeforces #349 div1
题解
首先需要看出方案数只和模式串的长度有关,和具体的字符无关。
由于模式串的长度和规模为 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;
}