BZOJ4888 [Tjoi2017]异或和 FFT或树状数组+二进制拆位

题面

戳这里

简要题解

做法一

因为所有数的和才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);
}
posted @ 2018-08-19 18:07  zykykyk  阅读(393)  评论(0编辑  收藏  举报