bzoj 4017: 小Q的无敌异或

4017: 小Q的无敌异或

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 593  Solved: 197
[Submit][Status][Discuss]

Description

背景
 
小Q学习位运算时发现了异或的秘密。
 
描述
 
小Q是一个热爱学习的人,他经常去维基百科(http://en.wikipedia.org/wiki/Main_Page)学习计算机科学。
 
就在刚才,小Q认真地学习了一系列位运算符(http://en.wikipedia.org/wiki/Bitwise_operation),其中按位异或的运算符 xor 对他影响很大。按位异或的运算符是双目运算符。按位异或具有交换律,即i xor j = j xor i。
 
他发现,按位异或可以理解成被运算的数字的二进制位对应位如果相同,则结果的该位置为0,否则为1,例如1(01) xor 2(10) = 3(11)。
 
他还发现,按位异或可以理解成数字的每个二进制位进行了不进位的加法,例如3(11) xor 3(11) = 0(00)。
 
于是他想到了两个关于异或的问题,这两个问题基于一个给定的非负整数序列A1, A2, ..., An,其中n是该序列的长度。
 
第一个问题是,如果用f(i, j)表示Ai xor Ai+1 xor ... xor Aj,则任意的1 <= i <= j <= n的f(i, j)相加是多少。
 
第二个问题是,如果用g(i, j)表示Ai + Ai+1 + ... + Aj,则任意的1 <= i <= j <= n的g(i, j)异或在一起是多少。
 
比如说,对于序列{1, 2},所有的f是{1, 2, 1 xor 2},加起来是6;所有的g是{1, 2, 1 + 2},异或起来是0。
 
他觉得这两个问题都非常的有趣,所以他找到了你,希望你能快速解决这两个问题,其中第一个问题的答案可能很大,你只需要输出它对998244353(一个质数)取模的值即可。
 

 

 

Input

第一行一个正整数n,表示序列的长度。
 
第二行n个非负整数A1, A2, ..., An,表示这个序列。
 

 

Output

两个整数,表示两个问题的答案,空格隔开,其中第一个问题的答案要对998244353(一个质数)取模。
 

 

Sample Input

2
1 2

Sample Output

6 0
 

此题求解该序列所有可能存在的子区间的异或和以及和的异或。
对于第一问求解区间的异或和。这一问在2017西安现场赛G题出现过,只不过把整个区间改为询问指定的区间。那么我们把每个数拆开,一位一位地来算贡献。在某一位上,我们做一个异或的前缀和,即把+换为^。那我们要求解某个区间[l,r]的异或值,即为sum(r)^sum(l-1)。包含0位置在内共有n+1个端点。我们统计下这个前缀和为1的端点数有k个,那么为0的就有(n+1-k)个,那么区间俩端点必须由不同数组成异或才为1(即sum(r)和sum(l-1)),这样的区间我们能选择k*(n+1-k),这即为第一问答案。
对于第二问。我们依旧拆开一位一位做。假如这是第k位,我们做%(2k+1)的前缀和。
如果第k位为1 ,那么(sum(r)sum(l1))mo2k+12k,这点显而易见。
用ans存这位是否为1,。我们从小到大枚举r,看满足这个等式的l-1是否为奇数个,如果是则ans^=1,否则不管。
但这东西不拆开来是不好做的。这个式子拆开 mod前的数并变换可以得出两个式子来限定sum(l-1)%(2k+1)的取值范围:
  1. sum(l1)mo2k+1(sum(r)mod2k+1)20sum(l1)mod2k+1 ,即 0sum(l1)mod2k+1(sum(r)mod2k+1)2k
  2. sum(l1)mod2k+1(sum(r)mod2k+1)2k+2k+1=(sum(r)mod2k+1)+2,sum(r)mod2k+1<sum(l1)mod2k+,即 sum(r)mod2k+1<sum(l1)mod2k+1(sum(r)mod2k+1)+2

我们先离散化所有前缀和的值。在枚举r的过程中,然后看对应区间内的数量是不是奇数个,这个可以用^的树状数组实现。或者权值线段树实现。

这样枚举了右端点后,就能得出ans,若为1则加上相应的2的幂次方作为答案贡献。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 998244353
 6 using namespace std;
 7 const int N=1e5+10;
 8 int bit[N];
 9 LL a[N];
10 LL order[N],found[N];
11 int n,m,k,cnt;
12 LL ans1,ans2;
13 void qy1(int mp)
14 {
15     LL num=0;
16     LL now=0;
17     for(int i=1;i<=n;i++)
18     {
19         now^=(a[i]>>mp)&1;
20         if(now)
21             num++;
22     }
23     ans1=(ans1+num*(n-num+1)%mod*(1LL<<mp)%mod)%mod;
24     return ;
25 }
26 void add(int i,int x)
27 {
28     if(!i) return ;
29     while(i<=cnt+1)
30     {
31         bit[i]^=x;
32         i+= i&-i;
33     }
34     return ;
35 }
36 int sum(int i)
37 {
38     int res=0;
39     while(i)
40     {
41         res^=bit[i];
42         i-= i&-i;
43     }
44     return res;
45 }
46 void qy2(int mp)
47 {
48     clr(bit);
49     int p;
50     found[0]=order[0]=0;
51     for(int i=1;i<=n;i++)
52     {
53         found[i]=(found[i-1]+a[i])%(1LL<<(mp+1));
54         order[i]=found[i];
55     }
56     sort(order,order+n+1);
57     cnt=unique(order,order+n+1)-order-1;
58     int ans=0;
59     for(int i=0;i<=n;i++)
60     {
61         p=lower_bound(order,order+cnt+1,found[i])-order;
62         if(order[p]!=found[i]) p--;
63         p++;
64         add(p,1);
65         ans^=sum(p);
66         p=lower_bound(order,order+cnt+1,found[i]-(1LL<<mp))-order;
67         if(order[p]!=found[i]-(1LL<<mp)) p--;
68         p++;
69         ans^=sum(p);
70         p=lower_bound(order,order+cnt+1,found[i]+(1LL<<mp))-order;
71         if(p==cnt+1 || order[p]!=found[i]+(1LL<<mp)) p--;
72         p++;
73         ans^=sum(p);
74     }
75     if(ans) ans2|=(1LL<<mp);
76     return ;
77 }
78 int main()
79 {
80     scanf("%d",&n);
81     for(int i=1;i<=n;i++)
82         scanf("%lld",&a[i]);
83     ans1=ans2=0;
84     for(int i=0;i<=20;i++) qy1(i);
85     for(int i=0;i<=40;i++) qy2(i);
86     printf("%lld %lld\n",ans1,ans2);
87     return 0;
88 }
View Code

 

posted @ 2017-11-01 07:09  hk_lin  阅读(972)  评论(0编辑  收藏  举报