bupt summer training for 16 #8 ——字符串处理
https://vjudge.net/contest/175596#overview
A.设第i次出现的位置左右端点分别为Li,Ri
初始化L0 = 0,则有ans = sum{ (L[i] - L[i-1]) * (n + 1 - Ri) }
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 8 int last = 0; 9 10 char s[5010]; 11 12 long long ans; 13 14 int main() { 15 scanf("%s", s + 1); 16 int n = strlen(s + 1); 17 for(int i = 1;i <= n;i ++) { 18 if(i + 3 <= n && s[i] == 'b' && s[i + 1] == 'e' && s[i + 2] == 'a' && s[i + 3] == 'r') { 19 ans += 1ll * (i - last) * (n + 1 - i - 3); 20 last = i; 21 i += 3; 22 } 23 } 24 cout << ans; 25 return 0; 26 }
B.AC自动机板子题,我的板子常数很大
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 7 const int maxn = 500010; 8 9 struct trie { 10 int next[maxn][26], fail[maxn], end[maxn]; 11 int L, root; 12 queue <int> q; 13 14 int newnode() { 15 for(int i = 0;i < 26;i ++) 16 next[L][i] = -1; 17 end[L] = 0; 18 return L ++; 19 } 20 21 void clear() { 22 L = 0; 23 root = newnode(); 24 } 25 26 int idx(char c) { 27 return c - 'a'; 28 } 29 30 void insert(char *buf) { 31 int len = strlen(buf), now = root, c; 32 for(int i = 0;i < len;i ++) { 33 c = idx(buf[i]); 34 if(next[now][c] == -1) 35 next[now][c] = newnode(); 36 now = next[now][c]; 37 } 38 end[now] ++; 39 } 40 41 void build() { 42 for(int i = 0;i < 26;i ++) { 43 if(next[root][i] == -1) 44 next[root][i] = root; 45 else { 46 fail[next[root][i]] = root; 47 q.push(next[root][i]); 48 } 49 } 50 while(!q.empty()) { 51 int now = q.front(); 52 q.pop(); 53 for(int i = 0;i < 26;i ++) { 54 if(next[now][i] == -1) 55 next[now][i] = next[fail[now]][i]; 56 else { 57 fail[next[now][i]] = next[fail[now]][i]; 58 q.push(next[now][i]); 59 } 60 } 61 } 62 } 63 64 int query(char *buf) { 65 int len = strlen(buf), now = root, res = 0, tmp; 66 for(int i = 0;i < len;i ++) { 67 tmp = now = next[now][idx(buf[i])]; 68 while(tmp != root) { 69 res += end[tmp]; 70 end[tmp] = 0; 71 tmp = fail[tmp]; 72 } 73 } 74 return res; 75 } 76 }; 77 78 trie ac; 79 80 int Case, n; 81 82 char buf[1000010]; 83 84 int main() { 85 scanf("%d", &Case); 86 while(Case --) { 87 scanf("%d", &n), ac.clear(); 88 while(n --) scanf("%s", buf), ac.insert(buf); 89 scanf("%s", buf), ac.build(); 90 printf("%d\n", ac.query(buf)); 91 } 92 return 0; 93 }
C.考察对KMP中next数组的理解,由一个串重复而来
所以就是max(i - next[i])
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 char s[1000010]; 8 9 int nex[1000010]; 10 11 int main() { 12 int i, j, ans, len; 13 while(~scanf("%s", s)) { 14 len = strlen(s); 15 nex[0] = -1; 16 ans = 0; 17 for(i = 1;i < len;i ++) { 18 j = nex[i - 1]; 19 while(j >= 0 && s[j + 1] != s[i]) j = nex[j]; 20 if(s[j + 1] == s[i]) { 21 nex[i] = j + 1; 22 ans = max(ans, i - nex[i]); 23 } 24 else nex[i] = -1, ans = max(ans, i + 1); 25 } 26 printf("%d\n", ans); 27 } 28 return 0; 29 }
D.令a[i] -= a[i + 1],题目就变成了
求数列中出现次数不小于2次的最长重复子串
后缀数组一个典型问题,二分子串长度即可
(考场上观察了半天手里板子的接口...然后放弃了)
E.先假设要由空串刷成串2,区间DP即可
dp[i][j]代表把 i-j 这段刷成串2需要的最少次数
可能分成几段分开去刷,所以不能直接ans = dp[L][R] (s1[L] != s2[L],s1[R] != s2[R])
利用f[i]代表 1-i 这段由串1刷成串2的最少次数
ans = f[n]
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 int n, dp[110][110], f[110]; 8 9 char s1[110], s2[110]; 10 11 int main() { 12 while(~scanf("%s %s", s1 + 1, s2 + 1)) { 13 n = strlen(s1 + 1); 14 memset(dp, 0x3f, sizeof dp); 15 for(int d = 1;d <= n;d ++) 16 for(int i = 1;i + d - 1 <= n;i ++) { 17 int j = i + d - 1; 18 if(i == j) dp[i][i] = 1; 19 else if(j == i + 1) dp[i][j] = 2 - (s2[i] == s2[j]); 20 else { 21 for(int k = i;k < j;k ++) 22 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] - (s2[i] == s2[k + 1])); 23 } 24 } 25 for(int i = 1;i <= n;i ++) { 26 f[i] = dp[1][i]; 27 if(s1[i] == s2[i]) f[i] = min(f[i - 1], f[i]); 28 else 29 for(int j = 1;j < i;j ++) 30 f[i] = min(f[i], f[j] + dp[j + 1][i]); 31 } 32 printf("%d\n", f[n]); 33 } 34 return 0; 35 }
F.简单的字典树
1 #include <cstdio> 2 #include <cstring> 3 4 const int maxn = 6000010; 5 6 struct trie { 7 int ch[maxn][2]; 8 int val[maxn]; 9 int siz; 10 11 void init() { 12 siz = 1; 13 memset(ch, 0, sizeof ch); 14 memset(val, 0, sizeof val); 15 } 16 17 void insert(int x) { 18 int i, u, c; 19 int num[40] = {0}; 20 for(i = 0;i < 30;i ++) 21 num[i] = x & (1 << i); 22 for(i = u = 0;i < 30;i ++) { 23 c = (num[29 - i] != 0); 24 if(!ch[u][c]) ch[u][c] = siz ++; 25 u = ch[u][c], val[u] ++; 26 } 27 val[0] ++; 28 } 29 30 void de1ete(int x) { 31 int i, u, c; 32 int num[40] = {0}; 33 for(i = 0;i < 30;i ++) 34 num[i] = x & (1 << i); 35 for(i = u = 0;i < 30;i ++) { 36 u = ch[u][(num[29 - i] != 0)]; 37 val[u] --; 38 } 39 val[0] --; 40 } 41 42 void query(int x) { 43 int i, u, c, ans = 0; 44 int num[40] = {0}; 45 for(i = 0;i < 30;i ++) 46 num[i] = x & (1 << i); 47 for(i = u = 0;i < 30;i ++) { 48 c = !(num[29 - i] != 0); 49 if(ch[u][c] && val[ch[u][c]]) ans |= (1 << (29 - i)), u = ch[u][c]; 50 else u = ch[u][!c]; 51 } 52 printf("%d\n", ans); 53 } 54 }; 55 56 trie now; 57 58 int n, x; 59 60 char str[5]; 61 62 int main() { 63 now.init(); 64 now.insert(0); 65 scanf("%d", &n); 66 while(n --) { 67 scanf("%s %d", str, &x); 68 switch(str[0]) { 69 case '+':now.insert(x);break; 70 case '-':now.de1ete(x);break; 71 case '?':now.query(x);break; 72 } 73 } 74 return 0; 75 }
G.
H.
I.
J.
K.最长回文子串,直接上马拉车
板子不长,mp[i] - 1 表示以 i 为中心的最长回文串长度
1 #include <map> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn = 1000010; 9 10 char str[3], s[maxn], ma[maxn], ans[maxn]; 11 12 int mp[maxn], l, len; 13 14 map <char, char> p; 15 16 void manacher() { 17 l = 0; 18 ma[l ++] = '$'; 19 ma[l ++] = '#'; 20 for(int i = 0;i < len;i ++) 21 ma[l ++] = s[i], ma[l ++] = '#'; 22 ma[l] = 0; 23 int mx = 0, id = 0; 24 for(int i = 0;i < l;i ++) { 25 mp[i] = mx > i ? min(mp[2 * id - i], mx - i) : 1; 26 while(ma[i + mp[i]] == ma[i - mp[i]]) mp[i] ++; 27 if(i + mp[i] > mx) mx = i + mp[i], id = i; 28 } 29 } 30 31 int main() { 32 while(~scanf("%s %s", str, s)) { 33 len = strlen(s); 34 manacher(); 35 int leng = 0, pos = -1; 36 for(int i = 0;i < l;i ++) 37 if(mp[i] > leng) 38 leng = mp[i], pos = i; 39 leng --; 40 if(leng == 1) { 41 puts("No solution!"); 42 continue; 43 } 44 if(pos & 1) { 45 printf("%d %d\n", pos / 2 - leng / 2, pos / 2 - leng / 2 + leng - 1); 46 for(int i = pos / 2 - leng / 2, j = 1;j <= leng;i ++, j ++) 47 ans[j] = s[i]; 48 } 49 else { 50 printf("%d %d\n", pos / 2 - leng / 2 - 1, pos / 2 - leng / 2 + leng - 2); 51 for(int i = pos / 2 - leng / 2 - 1, j = 1;j <= leng;i ++, j ++) 52 ans[j] = s[i]; 53 } 54 ans[leng + 1] = 0; 55 int dis = 'a' - str[0]; 56 for(int i = 0;i < 26;i ++) 57 p['a' + i] = 'a' + (i + dis + 26) % 26; 58 for(int i = 1;i <= leng;i ++) 59 ans[i] = p[ans[i]]; 60 puts(ans + 1); 61 } 62 return 0; 63 }
L.变换同D题,然后就是裸的KMP了
1 #include <map> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn = 1000010; 9 10 char str[3], s[maxn], ma[maxn], ans[maxn]; 11 12 int mp[maxn], l, len; 13 14 map <char, char> p; 15 16 void manacher() { 17 l = 0; 18 ma[l ++] = '$'; 19 ma[l ++] = '#'; 20 for(int i = 0;i < len;i ++) 21 ma[l ++] = s[i], ma[l ++] = '#'; 22 ma[l] = 0; 23 int mx = 0, id = 0; 24 for(int i = 0;i < l;i ++) { 25 mp[i] = mx > i ? min(mp[2 * id - i], mx - i) : 1; 26 while(ma[i + mp[i]] == ma[i - mp[i]]) mp[i] ++; 27 if(i + mp[i] > mx) mx = i + mp[i], id = i; 28 } 29 } 30 31 int main() { 32 while(~scanf("%s %s", str, s)) { 33 len = strlen(s); 34 manacher(); 35 int leng = 0, pos = -1; 36 for(int i = 0;i < l;i ++) 37 if(mp[i] > leng) 38 leng = mp[i], pos = i; 39 leng --; 40 if(leng == 1) { 41 puts("No solution!"); 42 continue; 43 } 44 if(pos & 1) { 45 printf("%d %d\n", pos / 2 - leng / 2, pos / 2 - leng / 2 + leng - 1); 46 for(int i = pos / 2 - leng / 2, j = 1;j <= leng;i ++, j ++) 47 ans[j] = s[i]; 48 } 49 else { 50 printf("%d %d\n", pos / 2 - leng / 2 - 1, pos / 2 - leng / 2 + leng - 2); 51 for(int i = pos / 2 - leng / 2 - 1, j = 1;j <= leng;i ++, j ++) 52 ans[j] = s[i]; 53 } 54 ans[leng + 1] = 0; 55 int dis = 'a' - str[0]; 56 for(int i = 0;i < 26;i ++) 57 p['a' + i] = 'a' + (i + dis + 26) % 26; 58 for(int i = 1;i <= leng;i ++) 59 ans[i] = p[ans[i]]; 60 puts(ans + 1); 61 } 62 return 0; 63 }