[LOJ 5516]無聊的數對

無聊的數對

題解

好水的題呀,爲什麼還是這句話???

額,首先,我們知道要使得a\oplus b的__builtin_parityll(即它在二進制下1的個數是否爲奇,一下簡稱parityll爲奇的話,a與b的parityll一定是不同的。

這,還是證一下吧。

我們設ap_{a}個1,bp_{b}個1,它們共有的1的個數爲p_{c},那麼它們異或後的1的個數爲p_{a}+p_{b}-2p_{c},它的奇偶性與p_{a}+p_{b}是相同的,所以要使得a\oplus b的1個數爲奇,p_{a}+p_{b}必定爲奇,於是p_{a}p_{b}的奇偶性不同。

於是答案就成了所有區間內偶數個1的個數乘上奇數個1的個數的積。

然後,我們發現數據規模爲2^{32}-1,明顯不能直接用暴力。我們就想到了線段樹維護所有已選的區間,加上一個動態開點就可以維護整個序列的值了。

時間複雜度是O\left(32n \right ),還是不忽略32了。

源碼

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<bitset>
#include<set>
using namespace std;
#define MAXN 1000005
typedef long long LL;
#define int LL
typedef pair<int,int> pii;
#define gc() getchar()
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;} 
int n,root,tot;
int lson[MAXN],rson[MAXN];
int tag[MAXN],odd[MAXN],even[MAXN];
int cal(int x){
	if(x&1LL)return x+1LL>>1LL;
	return (x>>1LL)+__builtin_parityll(x);
}
int calc(int l,int r){return cal(r)-cal(l-1);}
void insert(int &rt,int l,int r,int al,int ar){
	//printf("%d %d:%d %d\n",l,r,al,ar);
	if(!rt)rt=++tot;
	if(tag[rt])return ;
	if(al<=l&&r<=ar){
		rt=++tot;tag[rt]=1;
		odd[rt]=calc(l,r);
		even[rt]=r-l+1-odd[rt];
		//printf("%d %d:%d %d\n",l,r,odd[rt],even[rt]);
		return ;
	}
	int mid=l+r>>1LL;
	if(al<=mid)insert(lson[rt],l,mid,al,ar);
	if(ar>mid)insert(rson[rt],mid+1,r,al,ar);
	odd[rt]=odd[lson[rt]]+odd[rson[rt]];
	even[rt]=even[lson[rt]]+even[rson[rt]];
	tag[rt]|=tag[lson[rt]]&tag[rson[rt]];
	//printf("%d %d %d %d:%d %d\n",rt,tag[rt],l,r,odd[rt],even[rt]);
}
signed main(){
	read(n);
	for(int i=1;i<=n;i++){
		int l,r;read(l);read(r);
		insert(root,1,(1LL<<32LL),l,r);
		printf("%lld\n",odd[root]*even[root]);
	}
	return 0;
}
/*
*/

謝謝!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章