题目意思就是给定1~200个短的Primitive(长度1~10),以及一个长字符串(长度200,000以内),需要找出由这些Primitive任意重复连接形成的后者的最长前缀。
DP + Trie
设长字符串为seq,基本思路是若seq[0...i]是满足要求的前缀,那么seq[0...i+len]也是满足要求的前缀,len是各个Primitive的长度。
然后就是用Trie优化一下判断seq[i...i+len]是否在Primitive集合的过程。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 ID: xjtuacm1 3 PROG: prefix 4 LANG: C++ 5 */ 6 #include<iostream> 7 #include<stack> 8 #include<cstring> 9 #include<cstdio> 10 #include<queue> 11 #include<algorithm> 12 #include<map> 13 #include<set> 14 using namespace std; 15 16 const int PRISIZE = 205; 17 const int PRILEN = 10 + 1; 18 const int SEQLEN = 200005; 19 const int LINELEN = 76 + 2; 20 21 struct _trie 22 { 23 int next[26]; 24 int cnt; 25 } trie[PRISIZE * PRILEN]; 26 int trieNodeCnt; 27 28 int trieInit() 29 { 30 memset(trie, 0, sizeof(trie)); 31 trieNodeCnt = 1; 32 33 return 0; // trie tree's root 34 } 35 36 void trieAdd(int root, const char *str) 37 { 38 int p = root; 39 while(*str) 40 { 41 if(trie[p].next[*str - 'A'] == 0) 42 { 43 trie[p].next[*str - 'A'] = trieNodeCnt++; 44 } 45 p = trie[p].next[*str - 'A']; 46 str++; 47 } 48 trie[p].cnt += 1; 49 } 50 51 bool trieSearch(int root, const char* str, int len) 52 { 53 int p = root; 54 for(int i = 0; i!= len; i++) 55 { 56 if(trie[p].next[str[i] - 'A'] == 0) 57 return false; 58 59 p = trie[p].next[str[i] - 'A']; 60 } 61 62 return trie[p].cnt > 0; 63 } 64 65 char seq[SEQLEN]; 66 int seqlen = 0; 67 bool reach[SEQLEN]; // reach[i] = if seq[0...i) (length = i) can be composed from primitives. 68 69 int main(int argc, char *argv[]) 70 { 71 freopen("prefix.in", "r", stdin); 72 #ifndef USACO 73 freopen("prefix.out", "w", stdout); 74 #endif // USACO 75 76 int root = trieInit(); // root = 0 77 memset(reach, false, sizeof(reach)); 78 79 char temp[PRILEN]; 80 for(int i = 0; i!= PRISIZE; i++) 81 { 82 scanf("%s", temp); 83 if(temp[0] == '.') 84 break; 85 86 trieAdd(root, temp); 87 } 88 89 while(true) 90 { 91 scanf("%s", seq + seqlen); 92 int len = strlen(seq + seqlen); 93 if(len == 0) 94 break; 95 96 seqlen += len; 97 } 98 99 for(int i = 1; i!= PRILEN; i++) 100 { 101 reach[i] = trieSearch(root, seq, i); 102 } 103 104 for(int i = 0; i!= seqlen; i++) 105 { 106 if(reach[i]) 107 { 108 for(int j = 1; j!= PRILEN; j++) 109 { 110 if(trieSearch(root, seq + i, j)) 111 reach[i + j] = true; 112 } 113 } 114 } 115 116 for(int i = seqlen ; i != 0; i--) 117 { 118 if(reach[i]) 119 { 120 printf("%d\n", i); 121 return 0; 122 } 123 } 124 125 printf("0\n"); 126 return 0; 127 }
BTW,这是我第一次写Trie,感觉还挺顺手的。