(字典树3道水题)codeforces 665E&282E&514C
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 }