题目大概是给几个DNA片段,求构造一个长度n的字符串的方案数,要求这个字符串每个位置的字符都属于某个包含于此字符串的DNA片段。
把那些DNA片段建一个AC自动机。考虑状态的表示:
- dp[len][x][k]表示长度len且后缀状态为自动机结点x且后k位还不满足要求的方案数
- 然后转移就是向自动机上四个方向的结点走,如果下一步结点x'是某DNA的后缀且长度比k大,那就是转移到dp[len+1][x'][0]否则转移到dp[len+1][x'][k+1]。另外因为DNA最长10,所以第三维k不会超过10。
不过我还是看了别人代码才A掉这题。。忽略了某个结点不是一个DNA片段但其后缀可能是个DNA片段。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 using namespace std; 5 int tn,ch[111][4],fail[111],flag[111]; 6 int idx[128]; 7 void insert(char *s,int k){ 8 int x=0; 9 for(int i=0; s[i]; ++i){ 10 int y=idx[s[i]]; 11 if(ch[x][y]==0) ch[x][y]=++tn; 12 x=ch[x][y]; 13 } 14 flag[x]=k; 15 } 16 void getFail(){ 17 queue<int> que; 18 for(int i=0; i<4; ++i){ 19 if(ch[0][i]) que.push(ch[0][i]); 20 } 21 while(!que.empty()){ 22 int x=que.front(); que.pop(); 23 for(int i=0; i<4; ++i){ 24 if(ch[x][i]){ 25 que.push(ch[x][i]); 26 fail[ch[x][i]]=ch[fail[x]][i]; 27 flag[ch[x][i]]=max(flag[ch[x][i]],flag[ch[fail[x]][i]]); 28 } else ch[x][i]=ch[fail[x]][i]; 29 } 30 } 31 } 32 struct Node{ 33 int len,x,k; 34 Node(int _l=0,int _x=0,int _k=0):len(_l),x(_x),k(_k){} 35 }; 36 int d[1111][111][11]; 37 bool vis[1111][111][11]; 38 int main(){ 39 idx['A']=0; idx['C']=1; idx['G']=2; idx['T']=3; 40 char str[11]; 41 int n,m; 42 scanf("%d%d",&n,&m); 43 for(int i=0; i<m; ++i){ 44 scanf("%s",str); 45 insert(str,strlen(str)); 46 } 47 getFail(); 48 d[0][0][0]=1; 49 vis[0][0][0]=1; 50 queue<Node> que; 51 que.push(Node(0,0,0)); 52 while(!que.empty()){ 53 Node nd=que.front(); que.pop(); 54 int len=nd.len,x=nd.x,k=nd.k; 55 if(len==n) continue; 56 for(int i=0; i<4; ++i){ 57 if(k+1<=flag[ch[x][i]]){ 58 d[len+1][ch[x][i]][0]+=d[len][x][k]; 59 d[len+1][ch[x][i]][0]%=1000000009; 60 if(!vis[len+1][ch[x][i]][0]){ 61 vis[len+1][ch[x][i]][0]=1; 62 que.push(Node(len+1,ch[x][i],0)); 63 } 64 }else{ 65 if(k>=9) continue; 66 d[len+1][ch[x][i]][k+1]+=d[len][x][k]; 67 d[len+1][ch[x][i]][k+1]%=1000000009; 68 if(!vis[len+1][ch[x][i]][k+1]){ 69 vis[len+1][ch[x][i]][k+1]=1; 70 que.push(Node(len+1,ch[x][i],k+1)); 71 } 72 } 73 } 74 //vis[len][x][k]=0; //DAG 75 } 76 int res=0; 77 for(int i=0; i<=tn; ++i){ 78 res+=d[n][i][0]; 79 res%=1000000009; 80 } 81 printf("%d",res); 82 return 0; 83 }