【题目大意】
给你个模式串(每个长度≤15,1≤N≤20),串中只含有三种字母。求一长度为K(1≤K≤1000)的字符串,使得匹配数最大(重复匹配计多次),输出最大值。
【解题思路】
W老师给的题,然而我不会做。呜呜呜谢谢丁爷爷教我做题,神犇丁爷爷%%%。下面都是丁爷爷的话,和我没有关系。然而丁爷爷没有博客(也许是我不造?( •̀ ω •́ )y)现在正在码USACO给的标答…
COPYRIGHT@丁爷爷
代码是我自己的,因为是用指针写的会有点长,丁爷爷的代码只有60+。总之祝丁爷爷继续超神下去……
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #define lnum 3 7 using namespace std; 8 const int MAXK=1000; 9 const int MAXN=20*15+1; 10 int cnt=-1; 11 struct ACauto 12 { 13 int id; 14 ACauto* next[lnum]; 15 ACauto* fail; 16 ACauto() 17 { 18 id=++cnt; 19 for (int i=0;i<lnum;i++) next[i]=NULL; 20 fail=NULL; 21 } 22 }; 23 ACauto* rt=new ACauto(); 24 int go[MAXN][lnum];//编号为i的节点的三个后继的编号,如果不存在则为0 25 int combo[MAXN];//编号为i的节点及其后缀能够产生的最大匹配数 26 int dp[MAXN][MAXK];//在编号为i的节点上再走j步能够达到的最大值 27 int n,k; 28 29 void insert(ACauto* rt,char* str) 30 { 31 int len=strlen(str); 32 ACauto* now=rt; 33 for (int i=0;i<len;i++) 34 { 35 int index=str[i]-'A'; 36 if (now->next[index]==NULL) 37 { 38 now->next[index]=new ACauto(); 39 } 40 go[now->id][index]=now->next[index]->id; 41 now=now->next[index]; 42 } 43 combo[now->id]=1; 44 //在不包含后缀的情况下,当前结尾可以产生一个匹配 45 } 46 47 void buildfail(ACauto* rt) 48 { 49 queue<ACauto*> que; 50 que.push(rt); 51 while (!que.empty()) 52 { 53 ACauto* head=que.front();que.pop(); 54 for (int i=0;i<lnum;i++) 55 { 56 if (head->next[i]==NULL) continue; 57 if (head==rt) 58 head->next[i]->fail=rt; 59 else 60 { 61 ACauto* tmp=head->fail; 62 while (tmp!=NULL) 63 { 64 if (tmp->next[i]!=NULL) 65 { 66 head->next[i]->fail=tmp->next[i]; 67 break; 68 } 69 else 70 tmp=tmp->fail; 71 } 72 if (tmp==NULL) head->next[i]->fail=rt; 73 } 74 combo[head->next[i]->id]+=combo[head->next[i]->fail->id]; 75 //当前节点及其字符串后缀的节点均可能为模式串,故每次都要沿着指针计算这一步能够产生的新的匹配数。由于计算时累加的,只需沿fail指针走一步即可。 76 que.push(head->next[i]); 77 } 78 } 79 } 80 81 void init() 82 { 83 memset(go,0,sizeof(go)); 84 memset(combo,0,sizeof(combo)); 85 scanf("%d%d",&n,&k); 86 for (int i=0;i<n;i++) 87 { 88 char str[1000]; 89 scanf("%s",str); 90 insert(rt,str); 91 } 92 buildfail(rt); 93 } 94 95 void dp_process() 96 { 97 memset(dp,0,sizeof(dp)); 98 for (int i=0;i<=cnt;i++) dp[0][i]=combo[i]; 99 int cur=0; 100 for (int l=1;l<=k;l++) 101 { 102 cur^=1; 103 for (int i=0;i<=cnt;i++) 104 { 105 dp[cur][i]=0; 106 for (int j=0;j<lnum;j++) 107 dp[cur][i]=max(dp[cur][i],combo[i]+dp[cur^1][go[i][j]]); 108 } 109 } 110 printf("%d",dp[cur][0]); 111 } 112 113 int main() 114 { 115 init(); 116 dp_process(); 117 return 0; 118 }