首页 > 代码库 > 【NOIP模拟赛】与非 乱搞

【NOIP模拟赛】与非 乱搞

biubiu~~~

正解是线段树维护真值表,但是我觉得对于这道题来说乱搞就够了.......

我们发现如果我们把每一个数都一开始取反就会发现对于最后结果来说 x=x^1,x nand x=x|x ,x nand x nand x=x|x^1|x,x nand x nand x nand x=x|x^1|x^1|x.....而且我们还发现|0是无效,而且|1之后如有操作择从0开始若无操作则为1,那么我们可以维护我们处理过的x在序列上的前缀和以及他们从一开始进行操作然后每一位都停止一次的前缀答案和,这样我们在其所要求的区间上二分找到一个1之后就大体与我们预处理出来的东西一样了,当然还要讨论这个1是不是L如果是L还要讨论L+1是1还是0,如果第一位是1那么如果第二位是1我们就从第二位开始和预处理一样,如果我们第二位是0那么我们再二分找到第二个1在对其操作,而且从第一个1到第二个1的最后答案呈现0 1 0 1这样我们算偶数位就好了,对与我们L不是1的情况从第一位开始到第一个1,他的最后答案呈现出1 0 1 0 1,这样我们算奇数位就好了,这样我们插入O(1),查询O(log)就解决了。

#include <cstdio>#include <cstring>inline void read(int &sum){  register char ch=getchar();  for(sum=0;ch<0||ch>9;ch=getchar());  for(;ch>=0&&ch<=9;sum=(sum<<1)+(sum<<3)+ch-0,ch=getchar());}const int N=4000000;int a[N],s[N],S[N];int ans,len;int main(){  int T,opt,x,l,r,Now=0;  read(T);  while(T--){    read(opt);    if(opt==1){      read(x),x^=ans;      x^=1;      a[++len]=x;      Now|=x;      if(a[len])s[len]=s[len-1]+1;      else s[len]=s[len-1];      if(len==1) Now=a[1];      else S[len]=S[len-1]+Now,Now^=1;      continue;    }    read(l),read(r);    if(ans){      l=len-l+1,r=len-r+1;      l^=r^=l^=r;    }    int z=l,y=r,pos=r+1;    while(z<=y){      int mid=(z+y)>>1;      if(s[mid]-s[l-1]>0){        pos=mid,y=mid-1;      }else{        z=mid+1;      }    }    int len1=pos-l,len2=(r-l+1)-len1;    ans=0;    if(len1){      ans+=1;      ans+=(len1-1)>>1;      if(len2){        ans+=1;        ans+=S[r]-S[l+len1];      }    }else{      if(l==r){        ans=0;      }else{        if(a[l+1]){          ans=S[r]-S[l+1]+1;        }else{          z=l+1,y=r,pos=r+1;          while(z<=y){            int mid=(z+y)>>1;            if(s[mid]-s[l]>0){              pos=mid,y=mid-1;            }else{              z=mid+1;            }          }          len1=pos-l,len2=(r-l+1)-len1;          ans+=len1>>1;          if(len2){            ans+=1;            ans+=S[r]-S[l+len1];          }        }      }    }    ans=ans&1;    printf("%d\n",ans);  }}

 

【NOIP模拟赛】与非 乱搞