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; }