NEERC2013 HACK PROTECTION

想了好长时间。。。。

最后看了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;
}


你可能感兴趣的:(位运算,2013,NEERC)