CF1030E Vasya and Good Sequences

Vasya有n个64位二进制正整数,小R有一种魔法,它可以让一个二进制数的任意两位交换,比如它可以将7(...000111)变成11(...001011)或者22(...010110),等等。对于一个序列,如果Vasya可以通过对任意多个序列中的数(可以是0个)使用任意多次(可以是0次)这种魔法,使得序列中的所有数异或和得0,则称这是一个好的序列。给定n个数a_1,a_2,a_3...a_n,问有多少对(l,r),1<=l<=r<=n,使得a_l,a_l+1,...,a_r是好的序列。

蠢了……没发现只有64个数可以直接枚举……

首先我们把每一个数字转化为它二进制数里$1$的个数,然后满足以下两点的是一个好的序列

1.区间和为偶数

2.区间内的最大数小于等于区间和的一半

第一个可以用前缀和优化到$O(n)$

然后第二个,我们可以从$i$开始往前枚举,因为最多只会有64个$1$,所以只要往前推64位来判断是否有不满足条件的就行了

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 #define ll long long
 4 using namespace std;
 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 6 char buf[1<<21],*p1=buf,*p2=buf;
 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
 8 inline ll read(){
 9     #define num ch-'0'
10     char ch;bool flag=0;ll res;
11     while(!isdigit(ch=getc()))
12     (ch=='-')&&(flag=true);
13     for(res=num;isdigit(ch=getc());res=res*10+num);
14     (flag)&&(res=-res);
15     #undef num
16     return res;
17 }
18 const int N=3e5+5;
19 int c[N],sum[N],cnt[2]={1},n;ll ans;
20 inline int calc(){
21     ll x=read();int res=0;
22     while(x) ++res,x-=x&-x;
23     return res;
24 }
25 int main(){
26 //    freopen("testdata.in","r",stdin);
27     n=read();
28     for(int i=1;i<=n;++i){
29         c[i]=calc(),sum[i]=sum[i-1]+c[i];
30         ans+=cnt[sum[i]&1];
31         for(int j=i,k=i+1,mx=0;j>=1&&j>=i-64;--j){
32             while(k>j) cmax(mx,c[--k]);
33             if(mx*2>sum[i]-sum[j-1]&&((sum[i]&1)==(sum[j-1]&1))) --ans;
34         }
35         ++cnt[sum[i]&1];
36     }
37     printf("%lld
",ans);
38     return 0;
39 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9763334.html