题解:P9613 [CERC2019] K==S
fish_love_cat · · 题解
abc 出原题蚌埠住了。
多模匹配于是建 ACAM,然后把树边和 fail 树边看成转移边,于是可以 dp。
不能完整匹配所以在结束处打标记,把有标记的节点的转移边全部扔掉即可。记得要下传标记。
然后这个 dp 显然是可以变成转移矩阵的,于是把转移矩阵构造出来,跑一遍矩阵快速幂即可。
#include<bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
#define N 105
int tp;
int tr[N+5][35];
int tre[N+5];
int fail[N+5];
void ins(string s){
int flc=0;
for(int i=0;i<s.size();i++){
int nxt=s[i]-'a';
if(!tr[flc][nxt])
tr[flc][nxt]=++tp;
flc=tr[flc][nxt];
}
tre[flc]=1;
}
void fail_(){
queue<int>q;
for(int i=0;i<26;i++)
if(tr[0][i])q.push(tr[0][i]);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<26;i++)
if(tr[x][i]){
fail[tr[x][i]]=tr[fail[x]][i];
tre[tr[x][i]]|=tre[fail[tr[x][i]]];
q.push(tr[x][i]);
}else tr[x][i]=tr[fail[x]][i];
}
}
int a[105][105];
int b[105][105];
int ret[105][105];
void zc(){
memset(b,0,sizeof b);
for(int i=0;i<=tp;i++)
for(int j=0;j<=tp;j++)
for(int k=0;k<=tp;k++)
b[i][k]=(b[i][k]+a[i][j]*a[j][k]%mod)%mod;
for(int i=0;i<=tp;i++)
for(int j=0;j<=tp;j++)
a[i][j]=b[i][j];
}
void c(){
memset(b,0,sizeof b);
for(int i=0;i<=tp;i++)
for(int j=0;j<=tp;j++)
for(int k=0;k<=tp;k++)
b[i][k]=(b[i][k]+ret[i][j]*a[j][k]%mod)%mod;
for(int i=0;i<=tp;i++)
for(int j=0;j<=tp;j++)
ret[i][j]=b[i][j];
}
signed main(){
int n,k;
cin>>n>>k;
while(k--){
int x;
cin>>x;
string flc;
cin>>flc;
ins(flc);
}
fail_();
for(int i=0;i<=tp;i++)
for(int j=0;j<26;j++)
if(!tre[i]&&!tre[tr[i][j]])
ret[i][tr[i][j]]++,
a[i][tr[i][j]]++;
n--;
while(n){
if(n&1)
c();
n>>=1;
zc();
}
int flc=0;
for(int i=0;i<=tp;i++)
flc=(flc+ret[0][i])%mod;
cout<<flc;
return 0;
}
//「那个她最喜欢的,陪伴在她身边的,身为她未婚夫的温柔大哥哥已经不存在了。
// 如今沾染了些污秽的我,到底有什么脸去见她?」
//「是吗……这样啊。」
// 她感觉很落寞。
//「你们确实都会这么说呢。」