想了好长时间。。。。
最后看了dyf的题解直接拜到在地上了。
首先注意一下对于从一个固定起点计算and值,计算出来的结果一定是单调不下降的,并且只会有31种可能(2^31)!!!
xor值很好计算,做个前缀xor,我们可以O(1)得到区间的xor值
那么枚举and的起点,不断二分出and变化的位置,问题就变成询问区间内有多少xor值为固定值的问题了。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=100005;
int n,a[Maxn],c[Maxn],ad[Maxn][20],st[Maxn*2];
int l,r,mid,w,i,j,k,tot,cnt,d,x1,x2,t;
struct arr
{
int data,num;
bool operator <(const arr &a)const
{ return (data<a.data)||(data==a.data && num<a.num); }
} p[Maxn];
struct query
{
int l,r,x;
bool operator <(const query &a)const
{ return x<a.x; }
} qy[Maxn*40];
void build(){
for (i=1;i<=n;i++) ad[i][0]=a[i];
for (j=1;j<18;j++)
for (i=1;i<=n-(1<<(j-1));i++)
ad[i][j]=(ad[i][j-1]&ad[i+(1<<(j-1))][j-1]);
}
int get(int l,int r){
int t=st[r-l+1];
return (ad[l][t]&ad[r-(1<<t)+1][t]);
}
int main(){
freopen("hack.in","r",stdin);
freopen("hack.out","w",stdout);
scanf("%d",&n);
for (i=0;i<18;i++)
st[1<<i]=i;
for (i=1;i<=n;i++)
if (st[i]==0) st[i]=st[i-1];
for (i=1;i<=n;i++){
scanf("%d",&a[i]);
p[i].data = p[i-1].data^a[i];
p[i].num = i;
}
build();
for (i=1;i<=n;i++){
d=2147483647;
for (r=i-1;r<n;r=w){
d&=a[r+1];
qy[++tot].l=r+1;
l=r+1; r=n; w=r+1;
while (l<=r){
mid=(l+r)>>1;
t=get(i,mid);
if (t==d) l=mid+1, w=mid;
else r=mid-1;
}
qy[tot].r=w;
qy[tot].x=(d^p[i-1].data);
}
}
sort(qy+1,qy+tot+1);
sort(p+1,p+n+1);
long long ans=0;
for (i=1,j=1;i<=n;){
while (i<=n&&j<=tot&&p[i].data!=qy[j].x){
while (j<=tot && p[i].data>qy[j].x) j++;
while (i<=n && p[i].data<qy[j].x) i++;
}
for (cnt=0;i<=n&&p[i].data==qy[j].x;i++)
c[++cnt]=p[i].num;
for (k=j;j<=tot&&qy[j].x==qy[k].x;j++){
x1=lower_bound(c+1,c+cnt+1,qy[j].l)-c;
x2=upper_bound(c+1,c+cnt+1,qy[j].r)-c;
ans+=(long long)x2-x1;
}
}
printf("%I64d\n",ans);
return 0;
}
NEERC2013比赛中的位运算解题策略
本文介绍了在NEERC2013比赛中,如何利用位运算解决关于and和xor值的计算问题。作者提到,and值从固定起点开始计算会单调不降,存在31种可能;而xor值可以通过前缀xor快速求得。通过枚举and的起点并二分查找,可以高效解决区间内xor值匹配的问题。
758

被折叠的 条评论
为什么被折叠?



