4888 [Tjoi2017]异或和

Posted zykykyk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4888 [Tjoi2017]异或和相关的知识,希望对你有一定的参考价值。

题面

戳这里

简要题解

做法一

因为所有数的和才100w,所以我们可以直接求出所有区间和。

直接把前缀和存到一个权值数组,再倒着存一遍,大力卷积一波。

这样做在bzoj目前还过不了,但是luogu开O2,最慢的点才500ms左右。

#include<bits/stdc++.h>
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,u) for (register int i=first[u];i;i=last[i])
using namespace std;
typedef long long ll;
inline ll read(){
    ll x=0;int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!=‘-‘)&&(ch!=EOF)) ch=getchar();
    if (ch==‘-‘){f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
    return x*f;
}
const int N = 4e6+10;
int m,ans,pre[N];
struct node{
    double x,y;
    inline node operator + (const node &b)const{return (node){x+b.x,y+b.y};}
    inline node operator - (const node &b)const{return (node){x-b.x,y-b.y};}
    inline node operator * (const node &b)const{return (node){x*b.x-y*b.y,x*b.y+y*b.x};}
}a[N],b[N];
int n,l,pos[N];
inline void init(){
    for (n=1;n<=(pre[m]<<1);n<<=1,l++);
    For(i,0,n-1) pos[i]=(pos[i>>1]>>1)|((i&1)<<(l-1));
} 
const double pi = 3.1415926535897932;
inline void FFT(node *a,int f){
    For(i,0,n-1) if (i<pos[i]) swap(a[i],a[pos[i]]);
    node x,y;
    for (register int i=1;i<n;i<<=1){
        node wn=(node){cos(pi/i),f*sin(pi/i)};
        for (register int j=0;j<n;j+=i<<1){
            node w=(node){1,0};
            for (register int k=0;k<i;k++,w=w*wn) x=a[j+k],y=w*a[j+k+i],a[j+k]=x+y,a[j+k+i]=x-y;
        }
    }
    if (f<0) For(i,0,n-1) a[i].x=a[i].x/n+0.5;
}
int main(){
    m=read(),a[0].x=1;
    For(i,1,m) pre[i]=pre[i-1]+read(),++a[pre[i]].x;
    For(i,0,pre[m]) b[pre[m]-i].x=a[i].x;
    init();FFT(a,1),FFT(b,1);
    For(i,0,n-1) a[i]=a[i]*b[i];
    FFT(a,-1);
    //For(i,0,n-1) printf("%d ",(int)a[i].x);puts("");
    For(i,0,pre[m]) if ((int)a[i].x&1) ans^=(-(i-pre[m]));
    printf("%d",ans);
}

做法二

考虑拆位,大力分类讨论,再加一个树状数组维护下。

#include<bits/stdc++.h>
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,u) for (register int i=first[u];i;i=last[i])
using namespace std;
typedef long long ll;
inline ll read(){
    ll x=0;int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!=‘-‘)&&(ch!=EOF)) ch=getchar();
    if (ch==‘-‘){f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
    return x*f;
}
const int N = 1e6+10;
int n,cnt,Max,ans,pre[N];
struct BIT{
    int c[N];
    inline void Add(int x,int y){for (;x<=pre[n];x+=x&-x) c[x]+=y;}
    inline int Query(int x){int ans=0;for (;x;x-=x&-x) ans+=c[x];return ans;}
}t[2];
int main(){
    n=read();
    For(i,1,n) pre[i]=pre[i-1]+read();
    for (int i=1;i<=pre[n];i<<=1){
        cnt=Max=0;
        For(j,0,n){
            int x=((pre[j]&i)>0),y=pre[j]&(i-1);
            Max=max(Max,y),cnt+=t[x^1].Query(y+1)+t[x].Query(Max+1)-t[x].Query(y+1),t[x].Add(y+1,1);
        }
        For(j,0,pre[n]) t[0].c[j]=t[1].c[j]=0;
        ans|=(cnt&1)*i;
    }
    printf("%d",ans);
}

以上是关于4888 [Tjoi2017]异或和的主要内容,如果未能解决你的问题,请参考以下文章

4888 [Tjoi2017]异或和

[BZOJ4888][TJOI2017]异或和(树状数组)

Tjoi 2017 异或和

[TJOI 2017]异或和

[TJOI2017]异或和

P3760 [TJOI2017]异或和(BIT&位运算)