2018.09.23 codeforces 1053B. Vasya and Good Sequences(前缀和)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82826050

传送门
考试的时候卡了一会儿。
显然这个答案只跟二进制位为1的数量有关。
还有一个显然的结论。
对于一个区间 [ l , r ] [l,r] ,如果其中单个数二进制位为1的数量最大值不到区间所有数二进制位为1的数量之和的一半即 m a x n 2 s u m maxn*2\le sum ,并且sum是偶数那么这个区间是好的。
继续考虑,如果我们枚举左端点l和右端点r,那么当 s u m [ r 0 ] s u m [ l 1 ] 64 sum[r_0]-sum[l-1]\ge 64 之后,如果保持 l l 不变, r 0 r n r_0\le r\le n 时的答案可以直接通过前缀和预处理求出。
这样总时间复杂度是 O ( n 64 ) O(n*64)
代码:

#include<bits/stdc++.h>
#define N 300005
#define ll long long
using namespace std;
inline ll read(){
	ll ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans; 
}
int n;
ll a[N],sum[N],sum1[N],sum2[N],ans=0;
inline ll lowbit(ll x){return x&-x;}
inline int calc(ll x){
	int ret=0;
	while(x)x-=lowbit(x),++ret;
	return ret;
}
int main(){
	n=read(),sum2[0]=1;
	for(int i=1;i<=n;++i)sum[i]=sum[i-1]+(a[i]=calc(read()));
	for(int i=1;i<=n;++i)sum1[i]=sum1[i-1]+(sum[i]&1);
	for(int i=1;i<=n;++i)sum2[i]=sum2[i-1]+((sum[i]&1)^1);
	for(int r=1;r<=n;++r){
		ll maxn=a[r];
		int low=max(1,r-64);
		for(int l=r;l>=low;--l){
			maxn=max(maxn,a[l]);
			if((maxn<<1)<=(sum[r]-sum[l-1])&&(sum[r]&1)==(sum[l-1]&1))++ans;
		}
		if(low==1)continue;
		ans+=sum[r]&1?sum1[low-2]:sum2[low-2];
	}
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/82826050