題意
求長度爲m且不包含n個子串的種類數.
思路
參考自這個博客.
ac自動機+矩陣快速冪.
這兒有個結論.
給定一個有向圖,問從A點恰好走k步(允許重複經過邊)到達B點的方案數mod p的值
把給定的圖轉爲鄰接矩陣,即A(i,j)=1當且僅當存在一條邊i->j。令C=A*A
,那麼C(i,j)=ΣA(i,k)*A(k,j),實際上就等於從點i到點j恰好經過2條邊的路徑數(枚舉k爲中轉點)。類似地,CA(這裏的C已經是AA)的第i行第j列就表示從i到j經過3條邊的路徑數。
代碼
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
typedef long long ll;
int tot;
const int mod=100000;
int _size;
struct Matix{
ll m[110][110];
Matix(){
memset(m,0,sizeof(m));
}
Matix operator*(const Matix &m2){
Matix t;
for(int i=0;i<_size;++i)
for(int j=0;j<_size;++j)
for(int k=0;k<_size;++k)
t.m[i][j]=(t.m[i][j]+m[i][k]*m2.m[k][j])%mod;
return t;
};
Matix operator^(ll k) {
Matix x=*this,ans;
ans.m[0][0]=ans.m[1][1]=1;
while(k) {
if(k&1)
ans=ans*x;
x=x*x;
k>>=1;
}
return ans;
}
}g,res;
struct Trie{
int next[105010][130],fail[105010];
bool end[105010];
int root,L;
int idx(char s){
if(s=='A') return 0;
if(s=='T') return 1;
if(s=='C') return 2;
if(s=='G') return 3;
}
int newnode(){
for(int i=0;i<4;i++) next[L][i]=-1;
end[L++]=0;
return L-1;
}
void init(){
L=0;
root=newnode();
}
void insert(char buf[]){
int len=strlen(buf);
int now=root;
for(int i=0;i<len;i++){
int x=idx(buf[i]);
if(next[now][x]==-1)
next[now][x]=newnode();
now=next[now][x];
}
end[now]=1;
}
void build(){
queue<int> Q;
fail[root]=root;
for(int i=0;i<4;i++){
if(next[root][i]==-1)
next[root][i]=root;
else {
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
}
while(!Q.empty()){
int now=Q.front();
if(end[fail[now]]) end[now]=1;
Q.pop();
for(int i=0;i<4;i++){
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else {
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
tot=L;
for(int i=0;i<L;i++){
if(end[i]) continue;
for(int j=0;j<4;j++){
if(end[next[i][j]]) continue;
else g.m[i][next[i][j]]++;
}
}
}
} ac;
char buf[1000010];
int main(){
int n,m;scanf("%d%d",&n,&m);
ac.init();
for(int i=1;i<=n;i++){
scanf("%s",buf);
ac.insert(buf);
}
ac.build();
_size=tot;
for(int i=0;i<tot;i++)
res.m[i][i]=1;
while(m){
if(m&1) res=res*g;
g=g*g;
m>>=1;
}
long long ans=0;
for(int i=0;i<tot;i++){
ans=(ans+res.m[0][i])%mod;
}
printf("%lld\n",ans);
//system("pause");
return 0;
}