1. 程式人生 > >Newcoder 18 B.Xor(位運算+dp)

Newcoder 18 B.Xor(位運算+dp)

Description

給定長度為nn的非負整數序列aa,問有多少個長度為nn的非負整數序列bb

滿足:

biaib_i\le a_i

b1xorb2xor...xorbn=a1xora2xor...xoranb_1\ xor\ b_2\ xor\ ...\ xor\ b_n=a_1\ xor\ a_2\ xor\ ...\ xor\ a_n

答案對10000000091000000009取模

Input

第一行一個正整數nn

第二行nn個非負整數aia_i

(1n105,ai230)(1\le n\le 10^5,a_i\le 2^{30})

Output

輸出一個數字,表示答案

Sample Input

4 1 2 3 4

Sample Output

6

Solution

顯然bb序列和aa序列相等為一種合法方案,對於其餘方案,列舉使得某個bi<aib_i<a_i的最高位ll,即a,ba,b序列在比第ll位更高的位上均相同,而bib_i在第ll位是00aia_i在第ll位是11,顯然bib_i可以在前ll位隨意求值(均可保證bi<aib_i<a_i)使得前ll位均滿足異或和相等的限制,而其餘n

1n-1個數字在前ll位的取值只需保證不超過aa序列即可,那麼問題轉化為求nn個數字在第ll位取值使得bb序列不超過aa序列且至少存在一個位置使得bi<aib_i<a_i的方案數

dp[i][1/0][1/0]dp[i][1/0][1/0]表示前ii個數字已經確定,他們在第ll位的異或和為1/01/0,且前ii個數字中存在/不存在一個使得bi<aib_i<a_i的位置的方案數,考慮轉移

一.若aia_i在第ll位是11,那麼bib_i在第ll位有兩種選擇

1.b

ib_i在第ll位取00,假設aia_ill位的取值為xx,那麼只要bib_i在前ll位的取值不超過aia_i即可,有x+1x+1種方案,此時有轉移 dp[i][j][k]+=dp[i1][1j][k](x+1) dp[i][j][k]+=dp[i-1][1-j][k]\cdot (x+1) 2.bib_i在第ll位取00,那麼前llbib_i可以隨意取,此時有轉移 dp[i][j][1]+=dp[i1][j][k]2l dp[i][j][1]+=dp[i-1][j][k]\cdot 2^l 二.若aia_i在第ll位是00,那麼bib_i在第ll位只能取00,且較低位不能超過aia_i,此時有轉移 dp[i][j][k]+=dp[i1][j][k](x+1) dp[i][j][k]+=dp[i-1][j][k]\cdot (x+1) 那麼對於當前考慮的位ll,對答案的貢獻即為dp[n][res][1]2l\frac{dp[n][res][1]}{2^l},其中resres表示aia_i在第ll位的異或和,除以2l2^l的原因是需要有一個嚴格小於aia_ibib_i,在其他n1n-1個數字在前ll位取值固定之後,bib_i的前ll位需要做對應的取值使得前ll位的異或和也和aa序列相同

Code

 #include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=100005;
#define mod 1000000009
int add(int x,int y)
{
	x+=y;
	if(x>=mod)x-=mod;
	return x; 
}
int mul(int x,int y)
{
	ll z=1ll*x*y;
	return z-z/mod*mod;
}
int Pow(int x,int y)
{
	ll z=1;
	while(y)
	{
		if(y&1)z=mul(z,x);
		x=mul(x,x);
		y>>=1;
	}
	return z;
}
int n,a[maxn],dp[maxn][2][2];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	int ans=1;
	for(int l=30;l>=0;l--)
	{
		memset(dp,0,sizeof(dp));
		dp[0][0][0]=1;
		int res=0;
		for(int i=1;i<=n;i++)
			if((a[i]>>l)&1)
			{
				res^=1;
				a[i]-=(1<<l);
				for(int j=0;j<=1;j++)
					for(int k=0;k<=1;k++)
					{
						dp[i][j^1][k]=add(dp[i][j^1][k],mul(dp[i-1][j][k],a[i]+1));
						dp[i][j][1]=add(dp[i][j][1],mul(dp[i-1][j][k],1<<l));
					}
			}
			else
			{
				for(int j=0;j<=1;j++)
					for(int k=0;k<=1;k++)
						dp[i][j][k]=add(dp[i][j][k],mul(dp[i-1][j][k],a[i]+1));
			}
		ans=add(ans,mul(dp[n][res][1],Pow(1<<l,mod-2)));
	}
	printf("%d\n",ans);
	return 0;
}