题意
有
n
n
n 个单词,现在要生成
m
m
m 个字母的文本,问至少出现一个单词的文本有多少种。
n
≤
60
,
m
≤
100
,
∣
s
i
∣
≤
100
n\leq 60,m\leq 100,|s_i|\leq 100
n≤60,m≤100,∣si∣≤100
s
i
s_i
si 只包含大写英文字母。
分析
这算是一道很典型的
A
C
AC
AC 自动机上
d
p
dp
dp 的题目。
答案就是用
2
6
m
26^m
26m 减去一个单词都没出现过的。现在我们求一下后面的东西。
令
f
i
,
j
f_{i,j}
fi,j 表示长度为
i
i
i,来到节点
j
j
j 的方案数。
那么如果
t
r
j
,
k
tr_{j,k}
trj,k 不是末尾节点,就可以转移到
t
r
j
,
k
tr_{j,k}
trj,k。
初始条件
f
0
,
0
=
1
f_{0,0}=1
f0,0=1。
总复杂度是
O
(
26
n
∣
s
∣
m
)
O(26n|s|m)
O(26n∣s∣m)
代码如下
#include <bits/stdc++.h>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
struct custom_hash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
LL z = 1;
int read(){
int x, f = 1;
char ch;
while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
x = ch - '0';
while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
return x * f;
}
int ksm(int a, int b, int p){
int s = 1;
while(b){
if(b & 1) s = z * s * a % p;
a = z * a * a % p;
b >>= 1;
}
return s;
}
const int mod = 1e4 + 7, N = 6e3 + 5;
int f[105][N], ch[N][26], fail[N], v[N], cnt;
char s[N];
void insert(char *s){
int i, p = 0, c, n = strlen(s);
for(i = 0; i < n; i++){
c = s[i] - 'A';
if(!ch[p][c]) ch[p][c] = ++cnt;
p = ch[p][c];
}
v[p] = 1;
}
void get_fail(){
int i, a;
queue<int> q;
for(i = 0; i < 26; i++) if(ch[0][i]) q.push(ch[0][i]);
while(!q.empty()){
a = q.front(); q.pop();
for(i = 0; i < 26; i++){
if(ch[a][i]) v[ch[a][i]] |= v[ch[fail[a]][i]], fail[ch[a][i]] = ch[fail[a]][i], q.push(ch[a][i]);//一定要更新 v[ch[a][i]]!
else ch[a][i] = ch[fail[a]][i];
}
}
}
int main(){
int i, j, k, n, m, ans;
n = read(); m = read();
for(i = 1; i <= n; i++){
scanf("%s", s);
insert(s);
}
get_fail();
ans = ksm(26, m, mod);
f[0][0] = 1;
for(i = 0; i <= m; i++){
for(j = 0; j <= cnt; j++){
for(k = 0; k < 26; k++){
if(!v[ch[j][k]]){
f[i + 1][ch[j][k]] = (f[i + 1][ch[j][k]] + f[i][j]) % mod;
}
}
}
}
for(i = 0; i <= cnt; i++) ans = (ans - f[m][i]) % mod;
printf("%d", (ans + mod) % mod);
return 0;
}