usaco2.3 prefix trie树 + dp

来源:互联网 发布:java class命名 编辑:程序博客网 时间:2024/06/06 04:02

题目链接


题意:

给定一些 小 字符串,求得能由这些 小 字符串 拼接成的 大 字符串的 前缀 的最大值。


思路:

题目很直白显然,就是 trie 树 和 动态规划。


其实不用 trie 树也可以...但是怎么说呢

以前从来没写过 trie 树,想写一个试试看,于是就写了。

觉得这个时间还是挺有说服力的吧。(只是写得比较丑陋,请多多包涵

Executing...   Test 1: TEST OK [0.000 secs, 5160 KB]   Test 2: TEST OK [0.000 secs, 5160 KB]   Test 3: TEST OK [0.000 secs, 5160 KB]   Test 4: TEST OK [0.000 secs, 5160 KB]   Test 5: TEST OK [0.000 secs, 5160 KB]   Test 6: TEST OK [0.032 secs, 5164 KB]All tests OK.

至于 dp 的部分,从前往后和从后往前都可以

从前往后,can[]记录从第0位到第 i 位是否可被构成。之后对于特定的 i, 向前找已经判断为可以构成的 j, 并且判断 j ~ i 的这一段是否也可被构成,一旦找到一个这样的 j, i就是可行的。

从后往前,dp[]要记录从当前第 i 位开始向后连续的长度。之后对于特定的 i, 向后找所有可以构成的段 i ~ j,然后再加上从 j 开始可以向后延伸的长度,取所有的这些 和 里面的最大值为dp[i]。


个人还是比较偏爱从前向后的,因为比较好想也比较直白嘛(个人见解

那么为什么会有从前往后呢???

因为一开始写跪了啊(叹 第 6 组数据总是超时,于是就 参考 了别人的 blog...

百思不得其解为什么那样的 dp 就可行,为什么我的 dp 就不行,明明时间复杂度的话我应该还更胜一筹的吧(大概

最后最后最后发现,dp时 我忘了加一个约束条件,那就是 

j ~ i 的这一段长度 <= 小字符串的最大长度

这是十分重要的,因为缺了这个条件的我的程序,会面临要去找一个长度为 20w 的字符串在不在 trie 树 中的窘境,而事实上在那个样例中,最大需要找的字符串的长度也不超过 10,真是辛苦它了。


所以说细节决定成败,一点不假。


 

/*PROB: prefixLANG: C++ID: fan_0111*/#include <iostream>#include <cstdio>#include <string>#include <algorithm>using namespace std;struct node {char val;node* bro, *son;bool flag = false;};int tot = 0;node* init(char ch) {tot++;node* p = new node;p->val = ch;p->bro = p->son = NULL;return p;}void add(node*& head, string s) {int len = s.length();node* fa = NULL, * temp = head;for (int i = 0; i < len; ++i) {if (head == NULL) {head = init(s[i]);if (tot == 1) temp = head;if (i == len-1) head->flag = true;if (fa) fa->son = head;fa = head;head = head->son;continue;}else {node* prev;while (head && head->val != s[i]) {prev = head;head = head->bro;}if (head) {fa = head;if (i == len-1) head->flag = true;head = head->son;}else {head = init(s[i]);if (i == len-1) head->flag = true;prev->bro = head;fa = head;head = head->son;}}}head = temp;}bool find(node* head, string s) {int len = s.length();for (int i = 0; i < len; ++i) {while (head && head->val != s[i]) head = head->bro;if (!head)return false;if (i == len-1 && head->flag) return true;head = head->son;}return false;}bool can[200020];int dp[200020];int main() {freopen("prefix.in", "r", stdin);freopen("prefix.out", "w", stdout);string s;node* head = NULL;int maxLen = 0;while (cin >> s && s[0] != '.') {add(head, s);maxLen = max(maxLen, (int)s.length());}s = "";string line;while (cin >> line) s += line;int n = s.length();//for (int i = n-1; i >= 0; --i) {//for (int j = i; j-i+1 <= maxLen && j < n; ++j) {//if (!find(head, s.substr(i, j-i+1))) continue;//if (dp[i] < dp[j+1] + j - i + 1) dp[i] = dp[j+1] + j - i + 1;//}//}//cout << dp[0] << endl;int maxAns = -1;for (int i = 0; i < n; ++i) {for (int j = i; j >= 0 && i-j+1 <= maxLen; --j) {if ((can[j-1] || j == 0) && find(head, s.substr(j, i-j+1))) {can[i] = true;maxAns = max(maxAns, i);break;}}}cout << maxAns+1 << endl;fclose(stdin);fclose(stdout);return 0;}

0 0
原创粉丝点击