当前位置:   article > 正文

蓝桥杯每日一题(Tire树,字典树)

蓝桥杯每日一题(Tire树,字典树)

3485.最大异或和

思路:利用前缀数组S(异或)的思想,要求某个区间的数的异或和,可以用区间的两个端点的S值进行异或。(这个地方注意边界)。

怎么在限制范围内求两个Si值的异或的最大值呢。

利用字典树的思想,让字典树的cnt数组保存这个结点出现的次数。

在二叉树中找结果(具体做法就是从高位到低位尽量找和当前的数不同的分支),可能存在找到不在区间内的S值。我们可以从1到n遍历,删掉没有用的,而且后面也不会用到了。

debug :res*=2+1  和 res=res*2+1不一样,后者等于 res=res*(res*2+1);

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=100010*31,M=100010;
  4. //3485最大异或和
  5. int p[N][32];
  6. int cnt[N];
  7. int a[N],s[N];
  8. int n,m;
  9. int idx=0;
  10. //注意边界问题:si和sj异或后的结果是i到j-1的异或和
  11. //所以每次删除的是i-m-1位置的数。
  12. //因为从m+1就有需要删除的了此时考虑到用到了s0,所以先要把s0删除
  13. void insertt(int x,int t)
  14. {
  15. int f=0;//因为本来父节点就为0
  16. for(int i=30;i>=0;i--)
  17. {
  18. int u=x>>i&1;//获取第i位的二进制值
  19. if(!p[f][u])p[f][u]=++idx;
  20. f=p[f][u];
  21. cnt[f]+=t;//插入的时候某个节点出现一次就加1,要删除就-1
  22. }
  23. }
  24. int query(int x)
  25. {
  26. int f=0;
  27. int res=0;
  28. for(int i=30;i>=0;i--)
  29. {
  30. int u=x>>i&1;
  31. if(cnt[p[f][!u]])//和x的第i位不同的分支存在
  32. {
  33. //这个判断条件不可以直接用p数组。
  34. //可能已经把经过这个结点的数删没了,但是p还是有值的。
  35. res=2*res+1;
  36. f=p[f][!u];
  37. }
  38. else
  39. {
  40. res*=2;
  41. f=p[f][u];
  42. }
  43. }
  44. return res;
  45. }
  46. int main()
  47. {
  48. cin>>n>>m;
  49. for(int i=1;i<=n;i++)
  50. {
  51. cin>>a[i];
  52. s[i]=s[i-1]^a[i];
  53. }
  54. insertt(s[0],1);
  55. int ans=-1*N;
  56. for(int i=1;i<=n;i++)
  57. {
  58. if(i>m)insertt(s[i-m-1],-1);
  59. ans=max(ans,query(s[i]));
  60. insertt(s[i],1);
  61. }
  62. cout<<ans<<endl;
  63. }

835 Trie字符串统计(第一个独立写出的字典树)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. //835字符串统计
  4. const int N=100010;
  5. char f[N][30];
  6. int cnt[N];
  7. int idx=0;
  8. void insertt(string s)
  9. {
  10. int p=0;
  11. for(int i=0;i<s.length();i++)
  12. {
  13. if(!f[p][s[i]-'a'])f[p][s[i]-'a']=++idx;
  14. p=f[p][s[i]-'a'];
  15. }
  16. cnt[p]++;
  17. }
  18. int query(string s)
  19. {
  20. int p=0;
  21. for(int i=0;i<s.length();i++)
  22. {
  23. if(f[p][s[i]-'a'])p=f[p][s[i]-'a'];
  24. else return 0;
  25. }
  26. return cnt[p];
  27. }
  28. int main()
  29. {
  30. int n;
  31. cin>>n;
  32. while(n--)
  33. {
  34. string s;
  35. char c;
  36. cin>>c;
  37. cin>>s;
  38. if(c=='I')
  39. {
  40. insertt(s);
  41. }
  42. else
  43. {
  44. cout<<query(s)<<endl;
  45. }
  46. }
  47. }

143最大异或对

开始的时候在insert和query把获取各个位的边界和遍历方向弄错了;

(先做第一个后面两道都做的很快)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. //143最大异或对
  4. const int N=1e5+10,M=3e6+10;
  5. int f[M][3];
  6. int cnt[N];
  7. int idx=0;
  8. void insertt(int x)
  9. {
  10. int p=0;
  11. for(int i=30;i>=0;i--)
  12. {
  13. int u=x>>i&1;
  14. if(!f[p][u])f[p][u]=++idx;
  15. p=f[p][u];
  16. cnt[p]++;
  17. }
  18. }
  19. //找当前数的最大异或和
  20. int query(int x)
  21. {
  22. int p=0;
  23. int res=0;
  24. for(int i=30;i>=0;i--)
  25. {
  26. int u=x>>i&1;
  27. if(f[p][!u])
  28. {
  29. res=res*2+1;
  30. p=f[p][!u];
  31. }
  32. else
  33. {
  34. res*=2;
  35. p=f[p][u];
  36. }
  37. }
  38. return res;
  39. }
  40. int main()
  41. {
  42. int n;
  43. cin>>n;
  44. int ans=0;
  45. while(n--)
  46. {
  47. int num;
  48. cin>>num;
  49. insertt(num);
  50. ans=max(ans,query(num));
  51. }
  52. cout<<ans<<endl;
  53. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/253407
推荐阅读
相关标签
  

闽ICP备14008679号