Vasya and Good Sequences (Codeforces Round #512) 後綴和

Vasya and Good Sequences (Codeforces Round #512) 後綴和

嘛,蒟蒻第一次寫blog,也是第一次用c++好好寫程序,多多關照吧

原題:
Vasya可以將一個正整數的二進制表示中的任兩個數位調換位置,並且對每個數字都不限次數,最終希望得到一些異或和爲0的連續序列
給定n個正整數ai(n<=3e5,1<=ai<=1e18),求滿足題意的序列(l,r)個數

分析:
由於調換不限次數,易知只要統計每個數二進制下1的個數,並且目標序列只要滿足以下兩個條件即可:
①序列中1的個數和爲偶數
②序列中1最多的那個數不能比其他所有數1的個數加起來多

容易想到①通過後綴和操作(勉強算是dp?)可以O(n)完成,但是②當時卡了筆者一會,樸素的O(n^2)顯然會TLE
而後注意到每個ai都至少是1,而ai換成二進制最多也就60個1,因此只要序列長度>=61就已經自動滿足②了
設ai的上限爲M,則總體複雜度爲O(n*log(M))

#include <iostream>
#include <cmath>
#include <memory.h>
#include <bitset>
using namespace std;
const int MAXN=10+3e5;
int n,m,i,j,k,t,a[MAXN],f[MAXN][2];
long long x,ans=0;
int main()
{
	memset(f,0,sizeof(f));
	cin>>n;
	for (i=1;i<=n;i++)
	{
		cin>>x;
		t=0;
		while (x>0) 
		{
			t+=x&1;
			x=x>>1;
		}
		a[i]=t;
	}
	f[n+1][0]=0;
	f[n+1][1]=0;
	for (i=n;i>=1;i--)
	{
		if (a[i]&1)
		{
			f[i][0]=f[i+1][1];
			f[i][1]=1+f[i+1][0];
		}
		else
		{
			f[i][1]=f[i+1][1];
			f[i][0]=1+f[i+1][0];
		}
	}
	
	for (i=1;i<=n;i++)
	{
		t=a[i];
		m=a[i];
		k=min(n,i+61);
		for (j=i+1;j<=k;j++)
		{
			t+=a[j];
			m=max(m,a[j]);
			if ((t>=m*2) and (t%2==0)) ans++;
		}
		if (t%2) ans+=f[j][1];
		else ans+=f[j][0];
	}
	cout<<ans;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章