http://acm.scu.edu.cn/soj/problem.action?id=3030
给m个病毒串,问多少种不同的长度为n的基因序列不包含病毒串?
题解:
把所有病毒插入AC自动机的Tire树中,
我们把Tire树上的标记节点认为是一种包含了病毒的基因序列的后缀
因此我们建立Fail指针的时候,如果当前Fail指针所到达的地方为病毒后缀,那么当前状态即为非法的
然后我们可以在状态之间得到一个可否抵达的矩阵,
这个矩阵每自乘一次,就代表加入一个新的后缀在其中,也就是答案所求的递推式了
n很大,因此可以用快速幂优化
最终答案就是,自乘n次后,第一列的所有可能的后缀状态的和
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
#define per(ii,a,b) for(int ii=b;ii>=a;--ii)
#define forn(ii,x) for(int ii=head[x];ii;ii=e[ii].next)
using namespace std;
const int maxn=1e4+10,maxm=2e6+10;
const int INF=0x3f3f3f3f;
const ll mod=1e5;
//const double PI=acos(-1.0);
//head
int casn,n,m;
class matrix{public:
int a,b;
vector<vector<ll> > x;
matrix(int _a=1,int _b=1):
a(_a),b(_b),x(a,vector<ll>(b)){}
void element(int n){
a=b=n;x=matrix(n,n).x;
for(int i=0;i<n;i++)x[i][i]=1;
}
void fill(ll xx=0){
for(int i=0;i<a;i++)for(int j=0;j<b;j++)
x[i][j]=xx;
}
void fill(vector<vector<ll> > &y){
x=y;a=y.size();b=y[0].size();
}
matrix operator *(matrix &m){
matrix ans(a,m.b);
for(int i=0;i<a;i++)for(int j=0;j<m.b;j++)
for(int k=0;k<b;k++)if(x[i][k]&&m.x[k][j])
ans.x[i][j]=(ans.x[i][j]+(x[i][k]*m.x[k][j]%mod+mod))%mod;
return ans;
}
matrix operator +(matrix &m){
matrix ans(a,m.b);
for(int i=0;i<a;i++)for(int j=0;j<b;j++)
ans.x[i][j]=(x[i][j]+m.x[i][j]+mod)%mod;
return ans;
}
matrix operator -(matrix &m){
matrix ans(a,m.b);
for(int i=0;i<a;i++)for(int j=0;j<b;j++)
ans.x[i][j]=(x[i][j]-m.x[i][j]+mod)%mod;
return ans;
}
matrix pow(ll p){
matrix ans,t;ans.element(a);t.fill(x);
while(p){if(p&1) ans=t*ans;t=t*t;p>>=1;}
return ans;
}
};
const int csize=4,minc=0;
class autom{public:
#define nd node[now]
struct acnode{int flag,son[csize],fail;}node[maxn];
int cnt;
queue<int> que;
void clear(){
memset(node,0,sizeof node);
cnt=0;
}
void insert(char *s,int len=0){
if(!len)len=strlen(s);
int now=0;
rep(i,0,len-1){
int ch=s[i]-minc;
if(!nd.son[ch]) nd.son[ch]=++cnt;
now=nd.son[ch];
}
nd.flag=1;
}
void init(){
int now=0;
rep(i,0,csize-1) if(nd.son[i]) que.push(nd.son[i]);
while(!que.empty()){
now=que.front();que.pop();
rep(i,0,csize-1){
if(nd.son[i]) {
node[nd.son[i]].fail=node[nd.fail].son[i];
que.push(nd.son[i]);
}else nd.son[i]=node[nd.fail].son[i];
node[nd.son[i]].flag|=node[node[nd.fail].son[i]].flag;
}
}
}
}acam;
char p[1010];
int main(){IO;
ll n,m;
while(cin>>m>>n){
acam.clear();
rep(i,1,m) {
cin>>p;
int l=strlen(p);
rep(j,0,l-1){
if(p[j]=='A') p[j]=0;
else if(p[j]=='C') p[j]=1;
else if(p[j]=='G') p[j]=2;
else p[j]=3;
}
acam.insert(p,l);
}
acam.init();
int mt=acam.cnt;
vector<vector<ll> > _f(mt+1,vector<ll>(mt+1));
rep(i,0,mt){
if(acam.node[i].flag) continue;
rep(j,0,3) if(!acam.node[acam.node[i].son[j]].flag)
_f[i][acam.node[i].son[j]]++;
}
matrix f;f.fill(_f);
f=f.pow(n);
ll ans=0;
rep(i,0,mt) ans=(ans+f.x[0][i])%mod;
cout<<ans<<endl;
}
return 0;
}