(字典树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 }

 

转载于:https://www.cnblogs.com/tak-fate/p/6882812.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值