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);
}

原文地址:https://www.cnblogs.com/zykykyk/p/9502021.html

时间: 2024-10-13 20:32:48

4888 [Tjoi2017]异或和的相关文章

BZOJ 4888 [Tjoi2017]异或和

题解:对每一位分别考虑贡献 先求前缀和 按照二进制减法分类讨论,求出最终这一位是1还是0 用树状数组维护 注意:树状数组对0这个位置单独考虑 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int u=1000000; const int maxn=100009; int n; int ans; int a[maxn]; inline int lowbit(

【bzoj4888】: [Tjoi2017]异或和 BIT-乱搞

[bzoj4888]: [Tjoi2017]异或和 题目大意:给定一个序列,求这个序列所有的连续和的异或值.(n<=1e5 ai<=1e6) 想了各种奇怪的方法就是不会做啊啊啊.. Orz 参考了一下http://www.cnblogs.com/xiejiadong/p/6815269.html才会做的.. 恩因为不超过20位..所以可以考虑枚举所有连续和在第i位1的个数 预处理完前缀和就可以O(1)求出任意一个连续和.. 当考虑到第i位的时候,把前缀和扫一遍 当扫到第x个前缀和sum[x],

[TJOI2017]异或和

题目描述 在加里敦中学的小明最近爱上了数学竞赛,很多数学竞赛的题都是与序列的连续和相关的.所以对于一个序列,求出它们所有的连续和来说,小明觉得十分的 简单.但今天小明遇到了一个序列和的难题,这个题目不仅要求你快速的求出所有的连续和,还要快速的求出这些连续和的异或值.小明很快的就求出了所有的连续 和,但是小明要考考你,在不告诉连续和的情况下,让你快速求是序列所有连续和的异或值. 输入输出格式 输入格式: 第一行输入一个n,表示这序列的数序列 第二行输入n个数字a1,a2...an代表这个序列 0<

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

传送门 Solution 一位一位考虑,直接得到答案中第i为是否为1 Code //By Menteur_Hxy #include <ctime> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define Re register #defi

C的|、||、&amp;、&amp;&amp;、异或、~、!运算

位运算     位运算的运算分量只能是整型或字符型数据,位运算把运算对象看作是由二进位组成的位串信息,按位完成指定的运算,得到位串信息的结果. 位运算符有:     &(按位与).|(按位或).^(按位异或).~ (按位取反). 其中,按位取反运算符是单目运算符,其余均为双目运算符.     位运算符的优先级从高到低,依次为~.&.^.|, 其中~的结合方向自右至左,且优先级高于算术运算符,其余运算符的结合方向都是自左至右,且优先级低于关系运算符.    (1)按位与运算符(&) 

linux命令逻辑运算:与、或、非、异或

逻辑运算:与&.或|.非!.异或    与:只要有一个为假,结果一定为假    或:只要有一个为真,结果一定为真  1:真     0:假          1.与&      1 & 0 = 0    0 & 0 = 0 1 & 1 = 1    0 & 1 = 0    2.或      0|1 = 1    0|0 = 0 1|1 = 1    1|0 = 1 3.非!      !真 = 假    !假 = 真 4.异或      操作数相同则为假,

位运算之 C 与或非异或

位运算比较易混: 位运算之 C 与或非异或 与运算:& 两者都为1为1,否则为0 1&1=1,  1&0=0,  0&1=0,  0&0=0 或运算:| 两者都为0为0,否则为1 1|1 = 1,  1|0 = 1,  0|1 = 1, 0|0 = 0 非运算:~ 1取0,0取1 ~1 = 0, ~0 = 1 ~(10001) = 01110 异或运算:^ 两者相等为0,不等为1(易混淆) 1^1=0, 1^0=1, 0^1=1, 0^0=0 位移操作符:<&

HDU 5175 Misaki&#39;s Kiss again (异或运算,公式变形)

Misaki's Kiss again Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 201    Accepted Submission(s): 57 Problem Description After the Ferries Wheel, many friends hope to receive the Misaki's kiss

rman异机恢复

rman异机恢复 注意事项: 1.源数据库与目标数据库的目录结构相同 2.目标数据库只需要安装ORACLE软件(但是参数文件中指定的目录要创建) 3.要将源数据库的数据文件,参数文件,控制文件,密码文件,归档日志统统备份 1.源数据库备份 参数文件与控制文件自动备份 CONFIGURE CONTROLFILE AUTOBACKUP ON; CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/home/oracle/r