(字典树3道水题)codeforces 665E&282E&514C

时间:2022-12-30 13:17:15

665E

题意:

给一个数列和一个整数k,求这个数列中异或起来大于等于k的子串数量。

分析:

其实只要维护一个维护前缀和就行了,把前缀和加到字典树里,然后递归search一下,注意需要剪枝,不然会T, 

if(s + (1ll << (i + 1)) - 1 < k)return 0; 

这句话的意思是如果后面的二进制全都是1,都达不到k,就不用继续递归了。

代码:

 1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 #include <iostream>
5 #include <vector>
6
7
8 using namespace std;
9
10 typedef long long ll;
11
12 const int inf = 0x3f3f3f3f;
13 const int maxn = 30000010;
14
15
16 const int cha = 2;
17 const int MAXBITS = 30;
18 struct Trie_node {
19 ll cnt;
20 int nxt[cha];
21 } tree[maxn];
22
23 int nxt;
24
25 int newnode() {
26 memset(&tree[nxt], 0, sizeof(Trie_node));
27 return nxt++;
28 }
29
30 void Trie_insert(int val) {
31 int rt = 0;
32 for(int i = MAXBITS; i >= 0; i--) {
33 int id = (val & (1ll << i)) > 0;
34 if(!tree[rt].nxt[id]) {
35 tree[rt].nxt[id] = newnode();
36 }
37 rt = tree[rt].nxt[id];
38 tree[rt].cnt++;
39 }
40 }
41
42
43 void init() {
44 nxt = 1;
45 memset(tree, 0, sizeof(tree));
46 }
47
48 int n;
49 long long k;
50
51
52
53 ll Search(int val, int i, ll s, int rt) {
54 if(s >= k)return tree[rt].cnt;
55 if(s + (1ll << (i + 1)) - 1 < k)return 0;
56 if(i < 0)return 0;
57 int id = (val & (1ll << i)) > 0;
58 ll sum = 0;
59 if(tree[rt].nxt[id])sum += Search(val, i - 1, s, tree[rt].nxt[id]);
60 if(tree[rt].nxt[id ^ 1])sum += Search(val, i - 1, s + (1ll << i), tree[rt].nxt[id ^ 1]);
61 return sum;
62 }
63
64 int main() {
65 scanf("%d%I64d", &n, &k);
66 init();
67 Trie_insert(0);
68 int pre = 0;
69 int x;
70 ll ans = 0;
71 for(int i = 0; i < n; i++) {
72 scanf("%d", &x);
73 pre ^= x;
74 ans += Search(pre, MAXBITS, 0, 0);
75 Trie_insert(pre);
76 }
77 printf("%I64d\n", ans);
78 return 0;
79
80 }

282E

题意:

找到最大不相交前缀和后缀的异或和。

分析:

同样是维护前缀和,然后动态计算后缀和,在前缀和里找,不断更新ans为max就行了。

代码:

  1 #include <set>
2 #include <map>
3 #include <list>
4 #include <cmath>
5 #include <queue>
6 #include <vector>
7 #include <bitset>
8 #include <string>
9 #include <cctype>
10 #include <cstdio>
11 #include <cstring>
12 #include <cstdlib>
13 #include <iostream>
14 #include <algorithm>
15 #include <ctime>
16
17
18 using namespace std;
19
20 typedef long long ll;
21 typedef unsigned long long ull;
22 #define inf (0x3f3f3f3f)
23 #define lnf (0x3f3f3f3f3f3f3f3f)
24 #define eps (1e-6)
25 int sgn(double a) {
26 return a < -eps ? -1 : a < eps ? 0 : 1;
27 }
28
29 //--------------------------
30
31 const int maxn = 5000010;
32 const int MAXBITS = 40;
33
34
35 const int cha = 2;
36
37 struct Trie_node {
38 int cnt;
39 int nxt[cha];
40 } tree[maxn];
41
42 ll pre[100010];
43 ll num[100010];
44
45 int nxt;
46
47 void init() {
48 nxt = 1;
49 memset(tree, 0, sizeof(tree));
50 }
51
52 int newnode() {
53 memset(&tree[nxt], 0, sizeof(Trie_node));
54 return nxt++;
55 }
56
57 void Trie_insert(ll val) {
58 int rt = 0;
59 for(int i = MAXBITS; i >= 0; i--) {
60 int id = (val & (1ll << i)) > 0;
61 if(!tree[rt].nxt[id]) {
62 tree[rt].nxt[id] = newnode();
63 }
64 rt = tree[rt].nxt[id];
65 tree[rt].cnt++;
66 }
67 }
68
69
70 ll Search(ll val) {
71 int rt = 0;
72 ll res = 0;
73 for(int i = MAXBITS; i >= 0; i--) {
74 int id = (val & (1ll << i)) > 0;
75 if(tree[rt].nxt[id ^ 1]) {
76 res += (1ll << i);
77 rt = tree[rt].nxt[id ^ 1];
78 } else {
79 rt = tree[rt].nxt[id];
80 }
81 }
82 return res;
83 }
84
85
86
87 void solve() {
88 int n;
89 cin >> n;
90 init();
91 pre[0] = 0;
92 for(int i = 1; i <= n; i++) {
93 cin >> num[i];
94 pre[i] = pre[i - 1] ^ num[i];
95 }
96
97 ll suf = 0;
98 Trie_insert(0);
99 ll ans = 0;
100 for(int i = n; i >= 1; i--) {
101 ans = max(ans, Search(pre[i]));
102 suf ^= num[i];
103 Trie_insert(suf);
104 }
105 ans = max(ans, Search(0));
106 cout << ans << endl;
107 }
108
109
110 int main() {
111 solve();
112 return 0;
113 }

514C

题意:

给一个字典,判断字符串在字典中是否存在字符串只有一个位置的字符不同。

分析:

这题算是比较简单,只是应该坑点比较多,虽然是1A的。

我的做法是,先进行普通的Trie搜索,一旦发现错的,就进行另一个搜索。

需要处理一些细节的。

代码:

  1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 #include <iostream>
5 #include <vector>
6
7
8 using namespace std;
9
10 const int inf = 0x3f3f3f3f;
11 const int maxn = 4000010;
12 const int cha = 3;
13
14 struct Trie_node {
15 int cnt;
16 int nxt[cha];
17 bool exist;
18 } tree[maxn];
19
20 int nxt;
21
22
23 void init() {
24 nxt = 1;
25 memset(tree, 0, sizeof(tree));
26 }
27
28
29 int newnode() {
30 memset(&tree[nxt], 0, sizeof(Trie_node));
31 return nxt++;
32 }
33
34 void Trie_insert(string word) {
35 int rt = 0;
36 int len = word.length();
37 for(int i = 0; i < len; i++) {
38 int id = word[i] - 'a';
39 if(!tree[rt].nxt[id]) {
40 tree[rt].nxt[id] = newnode();
41 }
42 rt = tree[rt].nxt[id];
43 tree[rt].cnt++;
44 }
45 tree[rt].exist = true;
46 }
47
48 bool _search(int rt, string left) {
49 int len = left.length();
50 for(int i = 0; i < len; i++) {
51 int id = left[i] - 'a';
52 if(!tree[rt].nxt[id])return false;
53 rt = tree[rt].nxt[id];
54 }
55 return tree[rt].exist;
56 }
57
58 bool Trie_search(string word) {
59 int rt = 0;
60 int len = word.length();
61 for(int i = 0; i < len; i++) {
62 int id = word[i] - 'a';
63 if(i == len - 1) {
64 for(int j = 0; j < 3; j++) {
65 if(id == j)continue;
66 if(tree[rt].nxt[j] && tree[tree[rt].nxt[j]].exist) return true;
67 }
68 break;
69 }
70 for(int j = 0; j < 3; j++) {
71 if(id == j)continue;
72 if(tree[rt].nxt[j] && _search(tree[rt].nxt[j], word.substr(i + 1, len - i - 1))) {
73 return true;
74 }
75 }
76 if(!tree[rt].nxt[id])return false;
77 rt = tree[rt].nxt[id];
78 }
79 return false;
80 }
81
82
83
84 int n, m;
85
86 string str;
87
88 int main() {
89 cin >> n >> m;
90 init();
91 for(int i = 0; i < n; i++) {
92 cin >> str;
93 Trie_insert(str);
94 }
95 for(int i = 0; i < m; i++) {
96 cin >> str;
97 if(Trie_search(str))puts("YES");
98 else puts("NO");
99 }
100 return 0;
101
102 }