[JSOI2007]文本生成器【AC自动机+DP】
下定决心想要将这份爱意传达给你,与你在一起的每一刻总是那么值得珍藏,
你的存在左右着我的思绪,实在是不想错过这样的美好,
真的不和我在一起吗?
我的学术生涯,虽然有点奇妙,嗯,果然是开始了。导师是个副教授,叫我写\(vue\),嗯,也没问题,除了我一点也不会写\(vue\)之外。我从知网上下载他所有的论文时,忽然灵魂出窍灵光一现,想到一个海王见了都傻眼的点子。我的想法很大胆,我最近一直很大胆,不是不怕失败,不怕闯祸,不怕颜面尽失……只是,我渐渐明白了,只有肯在泥潭里打滚的野猪才能找到橡果。明天的任务就清晰了,一是学习\(vue\),二是研读手上的论文,三,最重要的,要给那几位教授发邮件轰炸了。我能预见我费心费力写的邮件可能被本校老师当做笑柄谈资,可能被外校老师一键删除,可是,我能预见,再也没有什么能阻止我了,就像我在开学前就加入\(ACM\)校队,就像我在军训前夕跌跌撞撞求加项目,就像我到武汉后就没有吃上一顿午饭,就像这个凌晨两点睡六点五十起床的日常……看吧,没有什么能阻止我。至于算法竞赛,我发现不觉间已更接近于深夜一种消遣了吧,就像春梦中的呓语。主动去追逐缥缈幻影里的鸿光吧,犯错的成本会越来越高的。标记好每个串的结尾点,跑AC自动机上按长度和节点方向\(DP\),求出不合法的情况数后容斥即可。
$click$ $for$ $codes$
# include "bits/stdc++.h"
using namespace std;
constexpr int N = 6003;
constexpr int mod = 1e4 + 7;
long long Pow(int x, int y) {
long long ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod) if(y & 1) ans = ans * x % mod;
return ans;
}
char str[N];
bool flag[N];
int ch[N][26], trie_index, fail[N];
struct Ahio_Corasick_Automation {
void insert(char *str) {
int len = strlen(str + 1), u = 0;
for(int i = 1; i <= len; ++i) {
int v = str[i] - 'A';
if(!ch[u][v]) ch[u][v] = ++trie_index;
u = ch[u][v];
}
flag[u] = true; // key 1
}
void build() {
queue<int> q;
for(int i = 0; i < 26; ++i) {
if(ch[0][i]) {
q.push(ch[0][i]);
}
}
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = 0; i < 26; ++i) {
if(ch[u][i]) {
fail[ch[u][i]] = ch[fail[u]][i];
q.push(ch[u][i]);
flag[ch[u][i]] |= flag[fail[ch[u][i]]]; // key 2
} else {
ch[u][i] = ch[fail[u]][i];
}
}
}
}
} AC;
long long f[N][N];
int main() {
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%s", str + 1);
AC.insert(str);
}
AC.build();
f[0][0] = 1; // key 3 // to assure length 1 -> val 1
for(int i = 1; i <= m; ++i) {
for(int j = 0; j <= trie_index; ++j) {
if(flag[j]) continue;
for(int k = 0; k < 26; ++k) {
f[i][ch[j][k]] = (f[i][ch[j][k]] + f[i - 1][j]) % mod;
}
}
}
long long ans = Pow(26, m);
for(int i = 0; i <= trie_index; ++i) {
if(flag[i]) continue;
ans = (ans - f[m][i] + mod) % mod;
}
printf("%lld", ans);
return 0;
}