zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    Hdu 3564 Another LIS 线段树+LIS
    利用ESLINT进行js 语法检查,以及局部安装时遇到的一些坑
    操作系统杂谈
    算法杂谈
    前端杂谈
    操作系统复习
    vue之——从彩笔的进步之路
    一丢丢学习之webpack4 + Vue单文件组件的应用
    计蒜客 2017复赛 百度地图导航
    electron打包之真的恶心
  • 原文地址:https://www.cnblogs.com/zykykyk/p/9502021.html
Copyright © 2011-2022 走看看