https://vjudge.net/contest/202728#problem/A
1. uva 11488 Hyper Prefix Sets
题意:给了一些string,定义其一个subset的价值为subset中所有string的longest common prefix(LCP)的长度 乘 subset的大小。让你找出最大的价值。
方法:将所有字符串插入字典树,可以边插边更新答案,或者查完后遍历字典树更新。
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 typedef pair<int, int> ii; 6 typedef pair<ll, ll> l4; 7 8 #define pb push_back 9 #define mp make_pair 10 11 12 const int maxn = 2e2+1; 13 char str[maxn], prefix[maxn]; 14 15 int read() 16 { 17 gets(str); 18 int ret = 0; 19 char *tmp = str; 20 while (*tmp) 21 { 22 ret = ret*10 + (*tmp-'0'); 23 ++tmp; 24 } 25 // cerr << "read " << ret << endl; 26 return ret; 27 } 28 29 const int N = 1e7+1; 30 int g[N][2], sz, cnt[N]; 31 inline int newnode() 32 { 33 memset(g[sz], 0, sizeof(g[sz])); 34 cnt[sz] = 0; 35 return sz++; 36 } 37 inline void init() 38 { 39 sz = 0; 40 newnode(); 41 } 42 inline void Max(int &a, const int &b) 43 { 44 if (a < b) 45 a = b; 46 } 47 int main() 48 { 49 int T = read(); 50 for (int kase = 1; kase <= T; ++kase) 51 { 52 int n = read(); 53 init(); 54 int ans = 0; 55 for (int i = 0; i < n; ++i) 56 { 57 gets(str); 58 int len = strlen(str); 59 for (int i = 0, j = 0; i < len; ++i) 60 { 61 int c = str[i]-'0'; 62 if (!g[j][c]) 63 g[j][c] = newnode(); 64 j = g[j][c]; 65 ++cnt[j]; 66 Max(ans, cnt[j]*(i+1)); 67 } 68 } 69 printf("%d ", ans); 70 } 71 72 }
2. uva 1519 Dictionary Sets
题意:给了一些string,让你生成一个dictionary。dictionary中的字符串可以是原来的string,也可以是形如prefix' + suffix', 其中prefix'要是某个原string的prefix,suffix'要是某个原string的suffix。问你dictionary的大小是多少
方法:
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 typedef pair<int, int> ii; 6 typedef pair<ll, ll> l4; 7 8 #define pb push_back 9 #define mp make_pair 10 11 12 const int N = 4e5+1, A = 26; 13 14 struct Trie 15 { 16 int g[N][A], sz, cnt[A]; 17 inline int newnode() 18 { 19 memset(g[sz], 0, sizeof(g[sz])); 20 return sz++; 21 } 22 inline void init() 23 { 24 sz = 0; 25 newnode(); 26 memset(cnt, 0, sizeof(cnt)); 27 } 28 inline void insert(char *str) 29 { 30 31 int len = strlen(str); 32 for (int i = 0, j = 0; i < len; ++i) 33 { 34 int c = str[i]-'a'; 35 if (!g[j][c]) 36 { 37 g[j][c] = newnode(); 38 if (i) 39 cnt[c] += 1; 40 } 41 j = g[j][c]; 42 } 43 } 44 inline void binsert(char *str) 45 { 46 47 int len = strlen(str); 48 for (int i = 0, j = 0; i < len; ++i) 49 { 50 int c = str[len-1-i]-'a'; 51 if (!g[j][c]) 52 { 53 g[j][c] = newnode(); 54 if (i) 55 cnt[c] += 1; 56 } 57 j = g[j][c]; 58 } 59 } 60 } prefix, suffix; 61 char str[50]; 62 inline bool read(int &a) 63 { 64 if (gets(str) == NULL) 65 return false; 66 char *tmp = str; 67 a = 0; 68 while (*tmp) 69 { 70 a = 10*a + *tmp-'0'; 71 ++tmp; 72 } 73 // cerr << "read " << a << endl; 74 return true; 75 } 76 int vis[A]; 77 int main() 78 { 79 int n; 80 while (read(n)) 81 { 82 prefix.init(); 83 suffix.init(); 84 memset(vis, 0, sizeof(vis)); 85 for (int i = 0; i < n; ++i) 86 { 87 gets(str); 88 prefix.insert(str); 89 suffix.binsert(str); 90 int len = strlen(str); 91 if (len == 1) 92 vis[str[0]-'a'] = 1; 93 } 94 ll ans = 1ll*(prefix.sz-1)*(suffix.sz-1); 95 for (int c = 0; c < 26; ++c) 96 ans -= 1ll*prefix.cnt[c]*suffix.cnt[c]-vis[c]; 97 printf("%lld ", ans); 98 } 99 }
3. uva 1399 puzzle
题意:告诉你字母表的大小和一些禁止串,让你找出最长的可行串。
方法:AC自动机上的DP
code:
4. uva 10298 power strings
题意:定义了string的power,给你若干询问,每次求出一个string的最大幂数。
方法:求周期问题
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 typedef pair<int, int> ii; 6 typedef pair<ll, ll> l4; 7 8 #define pb push_back 9 #define mp make_pair 10 11 const int maxn = 1e6+1; 12 13 char s[maxn]; 14 int f[maxn]; 15 16 int main() 17 { 18 while (gets(s)) 19 { 20 int len = strlen(s); 21 if (len == 1 && s[0] == '.') 22 break; 23 for (int i = 0, j = f[0] = -1; i < len; ++i, ++j) 24 { 25 while (j != -1 && s[i] != s[j]) 26 j = f[j]; 27 f[i+1] = j+1; 28 } 29 int pick = len-f[len]; 30 if (len % pick) 31 printf("%d ", 1); 32 else 33 printf("%d ", len/pick); 34 } 35 }
5. uva 10887 concatenation of languages
题意:给你两个string set A 和 B,让你求 ||{a+b, string a in A and string b in B}|| .
方法:哈希(?)。暴力枚举插入std::set<string>。注意有坑点,可能输入空串。
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 typedef pair<int, int> ii; 6 typedef pair<ll, ll> l4; 7 8 #define pb push_back 9 #define mp make_pair 10 11 12 string a[1500]; 13 char s[11]; 14 inline string get() 15 { 16 gets(s); 17 return string(s); 18 } 19 20 set<string> st; 21 int main() 22 { 23 int T; 24 scanf("%d", &T); 25 for (int kase = 1; kase <= T; ++kase) 26 { 27 int n, m; 28 scanf("%d %d", &n, &m); 29 get(); 30 for (int i = 0; i < n; ++i) 31 a[i] = get(); 32 st.clear(); 33 for (int i = 0; i < m; ++i) 34 { 35 string tmp = get(); 36 for (int j = 0; j < n; ++j) 37 st.insert(a[j]+tmp); 38 } 39 printf("Case %d: %d ", kase, (int)st.size()); 40 } 41 }
6. uva 11475 extend to palindrome
题意:给你一个字符串,让你在其后方加最少的字符,使得新字符串是个回文串。
方法:用str' 来表示 str的reverse, 注意原串S可以写成 A+B, 其中B是一个回文串(B = B', 可以为空)。最后得到的回文串为 A+B+A',A'为新增的部分。所以我们只需要B的长度最大,或者说S的后缀和S'的前缀的公共部分最大。很多种求法,匹配就可以。
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 typedef pair<int, int> ii; 6 typedef pair<ll, ll> l4; 7 8 #define pb push_back 9 #define mp make_pair 10 11 12 const int maxn = 1e5+1; 13 char s[maxn]; 14 int f[maxn]; 15 16 int main() 17 { 18 while (~scanf("%s", s)) 19 { 20 int n = strlen(s); 21 for (int i = 0, j = f[0] = -1; i < n; ++i, ++j) 22 { 23 while (j != -1 && s[n-1-i] != s[n-1-j]) 24 j = f[j]; 25 f[i+1] = j+1; 26 } 27 int i, j; 28 for (i = 0, j = 0; i < n; ++i) 29 { 30 while (j != -1 && s[i] != s[n-1-j]) 31 j = f[j]; 32 j += 1; 33 } 34 printf("%s", s); 35 while (j < n) 36 { 37 putchar(s[n-1-j]); 38 ++j; 39 } 40 putchar(' '); 41 } 42 }
7. uva 12338 anti-rhyme pairs
题意:给了一组string str[],多个询问,每个询问形如(i, j), 让你输出str[i] 和 str[j] 的最长公共前缀的长度(LCP)。
方法:建立字典树,用end[i] 表示 str[i] 在字典树上的终止位置(终止结点),h[node] 表示 node节点在字典树上的高度(即所对应字符串的长度),那么询问(i, j)的答案就是h[lca(end[i], end[j])]。所以对字典树求lca即可。
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 typedef pair<int, int> ii; 6 typedef pair<ll, ll> l4; 7 8 #define pb push_back 9 #define mp make_pair 10 11 12 const int N = 1e6+10; 13 const int A = 26; 14 vector<int> g[N]; 15 16 int ch[N][A], szs, v[100001]; 17 inline int newnode() 18 { 19 memset(ch[szs], 0, sizeof(ch[szs])); 20 g[szs].clear(); 21 return szs++; 22 } 23 inline void init() 24 { 25 szs = 0; 26 newnode(); 27 } 28 29 inline int insert(char *str) 30 { 31 int len = strlen(str); 32 int cur = 0; 33 for (int i = 0; i < len; ++i) 34 { 35 int c = str[i]-'a'; 36 if (!ch[cur][c]) 37 ch[cur][c] = newnode(), g[cur].pb(ch[cur][c]); 38 cur = ch[cur][c]; 39 } 40 return cur; 41 } 42 int sz[N], h[N], top[N], par[N]; 43 int n, m; 44 char str[N]; 45 void dfs(int cur) 46 { 47 sz[cur] = 1; 48 for (int i = 0; i < g[cur].size(); ++i) 49 { 50 int nxt = g[cur][i]; 51 par[nxt] = cur; 52 h[nxt] = h[cur]+1; 53 dfs(nxt); 54 sz[cur] += sz[nxt]; 55 } 56 } 57 void hl(int cur) 58 { 59 int son = -1; 60 int sonsz = 0; 61 for (int i = 0; i < g[cur].size(); ++i) 62 { 63 int nxt = g[cur][i]; 64 if (sz[nxt] > sonsz) 65 { 66 sonsz = sz[nxt]; 67 son = nxt; 68 } 69 } 70 if (son != -1) 71 top[son] = top[cur], hl(son); 72 for (int i = 0; i < g[cur].size(); ++i) 73 { 74 int nxt = g[cur][i]; 75 if (nxt != son) 76 top[nxt] = nxt, hl(nxt); 77 } 78 } 79 int lca(int a, int b) 80 { 81 while (top[a] != top[b]) 82 { 83 if (h[top[a]] < h[top[b]]) 84 swap(a, b); 85 a = par[top[a]]; 86 } 87 if (h[a] > h[b]) 88 return b; 89 else 90 return a; 91 } 92 int main() 93 { 94 int T; 95 scanf("%d", &T); 96 for (int kase = 1; kase <= T; ++kase) 97 { 98 printf("Case %d: ", kase); 99 scanf("%d", &n); 100 init(); 101 for (int i = 1; i <= n; ++i) 102 { 103 scanf("%s", str); 104 v[i] = insert(str); 105 } 106 par[0] = -1; 107 h[0] = 0; 108 top[0] = 0; 109 dfs(0); 110 hl(0); 111 scanf("%d", &m); 112 for (int i = 1; i <= m; ++i) 113 { 114 int uu, vv; 115 scanf("%d %d", &uu, &vv); 116 printf("%d ", h[lca(v[uu], v[vv])]); 117 } 118 } 119 }
8. uva 1556 disk tree
题意:给定多个文件路径,让你输出所有显示过的文件层次。
方法:
code:
9. uva 257 palinwords
题意:给你若干string,对于每一个string,如果他包含至少两个长度超过2、本质不同且互不包含的回文字串,就输出他。
方法:首先只需考虑长度为3和4的回文子串。
code:
10. uva 261 the window property
题意:定义一个string合法:如果对于每一个k <= strlen, 都有 ||set{ substring of length k }|| <= k+1。然后给你一个string,让你判断他是否合法,如果不合法输出第一个导致他不合法的位置(即这个位置之前的前缀是合法的。
方法:暴力,对于一个询问,记录下每个k值所对应的set。从左到右一次添加字符,每次添加第i(从1开始算)个字符,产生了i个新的substring,更新,判断是否合法。
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 typedef pair<int, int> ii; 6 typedef pair<ll, ll> l4; 7 8 #define pb push_back 9 #define mp make_pair 10 11 const int maxn = 1e2+1; 12 set<string> g[maxn]; 13 14 string str; 15 int solve() 16 { 17 int len = str.length(); 18 for (int i = 1; i <= len; ++i) 19 g[i].clear(); 20 for (int i = 0; i < len; ++i) 21 { 22 for (int k = 1; k <= i+1; ++k) 23 { 24 g[k].insert(str.substr(i+1-k, k)); 25 if (g[k].size() > k+1) 26 return i; 27 } 28 } 29 return -1; 30 } 31 char s[maxn]; 32 int main() 33 { 34 while (gets(s) != NULL) 35 { 36 str = string(s); 37 int ret = solve(); 38 if (ret == -1) 39 { 40 puts("YES"); 41 } 42 else 43 { 44 printf("NO:%d ", ret+1); 45 } 46 } 47 }
11. uva 282 rename
题意:
方法:
code:
12. uva 475 wild thing
题意:
方法:
code: