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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code
posted @ 2017-08-02 19:00  ztztyyy  阅读(184)  评论(0编辑  收藏  举报