题目大意:
用集合A中的串构造出一个串,使之让更多的setB中的串成为他的子串。
思路分析:
和 Codeforces 86C 差不多。
不过这里是要用A中的构造。
先用A 和 B的串构造一个自动机。然后对于A集合的尾结点给出一个最大后缀匹配,对于B集合的尾结点给一个权值。
dp[i][j][k] 表示已经构造出来了一个长度为i的串,现在走到了自动机的j结点,i长度后面有k个字符是没有匹配到的。
继续在自动机上走进行状态转移。
if(isword >= k +1 )dp [i+1] [j->next[d] ][0] = max(dp [i+1] [ j->next[d] ][0] , dp[i][j][k] + j->next[d]->val)...
else if( k+1 <= 10) dp [i+1] [j->next[d] ] [k+1 ] = max (dp[i+1][ j->next[d] ] [k+1] , dp [i][j][k] + j->next[d]->val)
...
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <utility> #include <string> #include <vector> #define inf 0x3f3f3f3f using namespace std; const int mod = 1000000009; const char tab = 'a'; const int max_next = 26; int rev[256]; struct trie { struct trie *fail; struct trie *next[max_next]; int isword,tip; int index; }; struct AC { trie *que[100005],*root,ac[100005]; int head,tail; int idx; trie *New() { trie *temp=&ac[idx]; for(int i=0;i<max_next;i++)temp->next[i]=NULL; temp->fail=NULL; temp->isword=0; temp->index=idx++; temp->tip=0; return temp; } void init() { idx=0; root=New(); } void Insert(trie *root,char *word,int len,int cmd){ trie *t=root; for(int i=0;i<len;i++){ if(t->next[word[i]-tab]==NULL) t->next[word[i]-tab]=New(); t=t->next[word[i]-tab]; } if(cmd)t->isword=len; else t->tip++; } void acbuild(trie *root){ int head=0,tail=0; que[tail++]=root; root->fail=NULL; while(head<tail){ trie *temp=que[head++],*p; for(int i=0;i<max_next;i++){ if(temp->next[i]){ if(temp==root)temp->next[i]->fail=root; else { p=temp->fail; while(p!=NULL){ if(p->next[i]){ temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL)temp->next[i]->fail=root; } //if(temp->next[i]->fail->isword) temp->next[i]->isword=max(temp->next[i]->isword,temp->next[i]->fail->isword); temp->next[i]->tip+=temp->next[i]->fail->tip; que[tail++]=temp->next[i]; } else if(temp==root)temp->next[i]=root; else temp->next[i]=temp->fail->next[i]; } } } void tra() { for(int i=0;i<idx;i++) { if(ac[i].fail!=NULL)printf("fail = %d ",ac[i].fail->index); for(int k=0;k<max_next;k++) printf("%d ",ac[i].next[k]->index); puts(""); } } }sa; char word[55]; int dp[65][1005][11]; int solve(int L) { memset(dp,-1,sizeof dp); dp[0][0][0]=0; for(int i=0;i<L;i++) { for(int j=0;j<sa.idx;j++) { for(int k=0;k<10;k++) { if(dp[i][j][k]<0)continue; for(int d=0;d<4;d++) { if(sa.ac[j].next[d]->isword>=k+1) dp[i+1][sa.ac[j].next[d]->index][0]=max(dp[i+1][sa.ac[j].next[d]->index][0],dp[i][j][k]+sa.ac[j].next[d]->tip); else if(k+1<=10) dp[i+1][sa.ac[j].next[d]->index][k+1]=max(dp[i+1][sa.ac[j].next[d]->index][k+1],dp[i][j][k]+sa.ac[j].next[d]->tip); } } } } int ans=0; for(int l=1;l<=L;l++) for(int i=0;i<sa.idx;i++) ans=max(ans,dp[l][i][0]); return ans; } int main() { rev['A']=0; rev['C']=1; rev['G']=2; rev['T']=3; int m,L,n; while(cin>>m>>n>>L) { sa.init(); for(int i=1;i<=m;i++) { cin>>word; sa.Insert(sa.root,word,strlen(word),1); } for(int i=1;i<=n;i++) { cin>>word; sa.Insert(sa.root,word,strlen(word),0); } sa.acbuild(sa.root); printf("%d\n",solve(L)); } return 0; }
Zoj 3535 Gao the String II (AC自动机+dp)
原文:http://blog.csdn.net/u010709592/article/details/39755599