2017.10.12 小Q的無敵異或 失敗總結
阿新 • • 發佈:2019-02-01
第一問是可以O(n)的
二進位制位是獨立的,所以直接分開算即可。。
記一個字首和,開桶裝0、1的個數 然後每次新加入一個點就直接更新就可以了
第二問就比較難了,,手玩只能發現最低位可以這麼搞,對於高位還要考慮借位情況,借位情況有0有1,就不好離散
但是這麼做是可以做出來的。。只是要在模意義下進行,,再考慮每次-的過程,都是一個字首和-比他靠前的字首和,
當差值>列舉次數時,顯然影響是1
差值要考慮進位的情況,,這樣似乎就形成了一個偏序關係,,就可以用樹狀陣列了。。
碼(借鑑):
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define P 998244353 ll ans,n,j,i,k,lin,er[50],he[50][100005],lie[100005],dui[100005],v[100005],a[100005],tong[100006],p[100005]; int lowbit(int a) { return a&(-a); } void jia(int o,int z) { for(;o<=dui[0];o+=lowbit(o)) { v[o]^=z; } } int cha(int o) { int ans=0; for(;o;o-=lowbit(o)) { ans^=v[o]; }return ans; } int find(ll o) { if(o<0)return 0; int l=1,r=dui[0]+1; while(l+1<r) { int mid=(l+r)>>1; if(dui[mid]<=o)l=mid; else r=mid; } return l; } int main() { er[0]=1; for(i=1;i<=40;i++) er[i]=er[i-1]*2; scanf("%lld",&n); for(i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(i=0;i<=20;i++) for(j=1;j<=n;j++) { he[i][j]=he[i][j-1]^(a[j]&er[i]); if(he[i][j]&er[i])tong[i]++; } for(i=0;i<=20;i++) { for(j=1;j<=n;j++) { ans=1ll*(ans+1ll*tong[i]*er[i])%P; if(a[j]&er[i]) { tong[i]=(n-j)-(tong[i]-1); } } } printf("%lld ",ans); ans=0; for(i=1;i<=n;i++)he[0][i]=he[0][i-1]+a[i]; for(k=0;k<=37;k++){ for (i=0; i<=n; i++) tong[i]=p[i]=he[0][i]&(er[k+1]-1); dui[0]=0; sort(tong,tong+n+1); dui[++dui[0]]=tong[0]; memset(v,0,sizeof(v)); for (i=1; i<=n; i++) if (tong[i]!=tong[i-1]) dui[++dui[0]]=tong[i]; int lin=0; for (i=0; i<=n; i++){ lin^=cha(find(p[i]-er[k]))^cha(find(p[i]))^cha(find(p[i]+er[k])); //cout<<er[k]<<" "<<lin<<" "; jia(find(p[i]),1); } //cout<<lin<<endl; if (lin) ans|=er[k]; } printf("%lld",ans); }