前言:
是我为数不多自己做出来的紫题吧..(但是也给了我很多警醒--一定要想清楚再写代码.)
思维:
这题思路不复杂.它要你计数,那你就按照它给的去计数就好了,把异或的前缀存起来,这样的好处就是你每次异或的时候鸭,它就是一个二元组.然后放字典树上模拟就好了...(为什么我要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;
}
京公网安备 11010502036488号