前言:
是我为数不多自己做出来的紫题吧..(但是也给了我很多警醒--一定要想清楚再写代码.)
思维:
这题思路不复杂.它要你计数,那你就按照它给的去计数就好了,把异或的前缀存起来,这样的好处就是你每次异或的时候鸭,它就是一个二元组.然后放字典树上模拟就好了...(为什么我要debug那么久啊!
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+500,M=2e7; ll pre[N]; int son[M][2];//当前节点子节点是0/1的节点是哪个. int id=1,p;int num[M];//统计下这个位节点有多少. void insert(ll x) { p=0; for(ll i=31;i>=0;i--) { ll pos=(x>>i&1); int &s=son[p][pos]; if(!s) s=id++; num[s]++; p=s; } } ll cal(ll x,ll k) { p=0;int wz;ll Res=0; for(ll i=31;i>=0;i--) { ll pos=(x>>i&1); ll res=(k>>i&1); if(res==1) { wz=!pos; if(i==0) Res+=num[son[p][!pos]]; } else { wz=pos; if(son[p][!pos]) Res+=num[son[p][!pos]]; if(i==0) Res+=num[son[p][pos]]; }int &s=son[p][wz];if(!s) break; p=s; }return Res; } int main() { int n;ll k,ans=0; scanf("%d%lld",&n,&k);//最高位最多是31 for(int i=1;i<=n;i++) { pre[i]^=pre[i-1]; int x;scanf("%d",&x); pre[i]^=x; ans+=cal(pre[i],k); if(pre[i]>=k) ans++; insert(pre[i]); }printf("%lld\n",ans); return 0; }