1、UVa 1401 Remember the Word
题意:给出n个字符串集合,问其有多少种组合方式形成目标字符串。
思路:对n个字符串集合建立Trie树,保存每个结点的字符串的顺序编号。然后对这棵树查找目标字符串每一个后缀的前缀字符串,累加。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 const int MOD = 20071027; 8 struct Trie 9 { 10 int word[4001 * 100][26]; 11 int ex[4001 * 100]; 12 int size; 13 14 void clear() 15 { 16 memset(word[0], 0, sizeof(word[0])); 17 size = 1; 18 ex[0] = 0; 19 } 20 21 void insert(char *s, int v) 22 { 23 int Now = 0, curchr; 24 for (int i = 0; s[i] != ‘\0‘; i++) 25 { 26 int c = s[i] - ‘a‘; 27 if (!word[Now][c]) 28 { 29 memset(word[size], 0, sizeof(word[size])); 30 ex[size] = 0; 31 word[Now][c] = size++; 32 } 33 Now = word[Now][c]; 34 } 35 ex[Now] = v; 36 } 37 38 int search(char *s, int len, vector<int>& ans) 39 { 40 int u = 0, c; 41 for (int i = 0; s[i] != ‘\0‘&&i<len; i++) 42 { 43 c = s[i] - ‘a‘; 44 if (!word[u][c])return 0; 45 u = word[u][c]; 46 if (ex[u]) 47 ans.push_back(ex[u]); 48 } 49 } 50 } tree; 51 52 char s[300001]; 53 char tmp[101]; 54 int dp[300001]; 55 int n; 56 int ll[4001];//记录每个字符串的长度 57 int main() 58 { 59 int Case = 1; 60 while (~scanf("%s",s)) 61 { 62 scanf("%d", &n); 63 tree.clear(); 64 memset(dp, 0, sizeof(dp)); 65 int len = strlen(s); 66 67 for (int i = 0; i<n; i++) 68 { 69 scanf("%s", tmp); 70 ll[i + 1] = strlen(tmp); 71 tree.insert(tmp, i + 1); 72 } 73 dp[len] = 1; 74 for (int i = len - 1; i >= 0; i--) 75 {//找下标为i~len-1的子字符串的前缀字符串 76 vector<int>ans; 77 tree.search(s + i, len - i, ans); 78 for (int j = 0; j<ans.size(); j++) 79 dp[i] = (dp[i] + dp[i + ll[ans[j]]]) % MOD; 80 } 81 printf("Case %d: %d\n", Case++, dp[0]); 82 } 83 return 0; 84 }
2、UVA 11732 strcmp() Anyone?
题意:给n个长度不超过1000的字符串,两两字符串比较,某一位相同比较2次,不相同比较1次,问需要比较多少次。
思路:左儿子右兄弟法表示Trie树。向右找相同字符,向左添加新字符,同一兄弟层表示在同一位的字符。
参考:http://www.cnblogs.com/sineatos/p/3888815.html
1 #include <cstdio> 2 #include <cstring> 3 #define MAXN 4001010 4 #define ll long long 5 using namespace std; 6 //左儿子右兄弟表示字典树 7 int head[MAXN];// head[i]为第i个结点的左儿子编号 8 int next[MAXN];// next[i]为第i个结点的右兄弟编号 9 int tot[MAXN];// tot[i]为第i个结点为根的子树包含的叶结点(即以包含其的前缀的字符串个数)总数 10 int ed[MAXN];// ed[i]为第i个结点结束的字符串的个数 11 char ch[MAXN];// ch[i]为第i个结点上的字符 12 int sz; 13 ll sum; 14 void init() 15 {// 初始时只有一个根结点 16 sz = 1; head[0] = next[0] = tot[0] = 0; sum = 0; 17 } 18 19 void insert(char *s) 20 { 21 int u, v, n = strlen(s); 22 u = 0; 23 for (int i = 0; i<n; i++) 24 { 25 bool f = 0; 26 for (v = head[u]; v != 0; v = next[v]) 27 {//找字符s[i] 28 if (ch[v] == s[i]) 29 { 30 f = 1; break; 31 } 32 } 33 if (!f) 34 {//如果没找到,新建结点 35 v = sz++; 36 tot[v] = 0; 37 ed[v] = 0; 38 ch[v] = s[i]; 39 next[v] = head[u];//插入首部 40 head[u] = v; 41 head[v] = 0; 42 } 43 u = v; 44 sum += tot[v] * 2; 45 tot[v]++; 46 } 47 sum += ed[u]; 48 ed[u]++; 49 } 50 int main() 51 { 52 int n; 53 char s[1002]; 54 int Case = 1; 55 while(~scanf("%d", &n)&&n) 56 { 57 init(); 58 for (int i = 0; i<n; i++) 59 { 60 scanf("%s", s); 61 insert(s); 62 } 63 printf("Case %d: %lld\n", Case++, sum + n*(n - 1) / 2); 64 } 65 return 0; 66 }
3、uva 11488 Hyper Prefix Sets
题意:求n个给出的01串的最长公共前缀的长度*n的值。
思路:字典树,每次插入一个新的01串,累计每个结点的前缀的长度。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 6 const int maxn = 10000010; 7 const int Char_size = 2; 8 struct Trie 9 { 10 int word[maxn][Char_size];//结点 11 int val[maxn];//附加信息 12 int size;//总结点数 13 int ans; 14 15 void Init() 16 { 17 memset(word[0], 0, sizeof(word[0])); 18 size = 1; 19 val[0] = 0; 20 ans = 0; 21 } 22 int getID(char c) 23 { 24 return c - ‘0‘; 25 } 26 void Insert(char *s) 27 { 28 int now = 0, curchr; 29 for (int i = 0; s[i] != ‘\0‘; i++) 30 { 31 int pos =getID(s[i]); 32 if (!word[now][pos]) 33 { 34 memset(word[size], 0, sizeof(word[size])); 35 val[size] = 0; 36 word[now][pos] = size++; 37 } 38 now = word[now][pos]; 39 val[now] += i + 1;//累加到该结点的前缀的长度 40 ans = max(ans, val[now]); 41 } 42 } 43 }tree; 44 45 char str[maxn]; 46 int main() 47 { 48 int t; 49 scanf("%d", &t); 50 while (t--) 51 { 52 tree.Init(); 53 int n; 54 scanf("%d", &n); 55 while (n--) 56 { 57 scanf("%s", str); 58 tree.Insert(str); 59 } 60 printf("%d\n", tree.ans); 61 } 62 return 0; 63 }
时间: 2024-11-06 01:21:09