Description
给定长度为 n n n的非负整数序列 a a a,问有多少个长度为 n n n的非负整数序列 b b b,
满足:
b i ≤ a i b_i\le a_i bi≤ai
b 1 x o r b 2 x o r . . . x o r b n = a 1 x o r a 2 x o r . . . x o r a n b_1\ xor\ b_2\ xor\ ...\ xor\ b_n=a_1\ xor\ a_2\ xor\ ...\ xor\ a_n b1 xor b2 xor ... xor bn=a1 xor a2 xor ... xor an
答案对 1000000009 1000000009 1000000009取模
Input
第一行一个正整数 n n n
第二行 n n n个非负整数 a i a_i ai
( 1 ≤ n ≤ 1 0 5 , a i ≤ 2 30 ) (1\le n\le 10^5,a_i\le 2^{30}) (1≤n≤105,ai≤230)
Output
输出一个数字,表示答案
Sample Input
4
1 2 3 4
Sample Output
6
Solution
显然 b b b序列和 a a a序列相等为一种合法方案,对于其余方案,枚举使得某个 b i < a i b_i<a_i bi<ai的最高位 l l l,即 a , b a,b a,b序列在比第 l l l位更高的位上均相同,而 b i b_i bi在第 l l l位是 0 0 0而 a i a_i ai在第 l l l位是 1 1 1,显然 b i b_i bi可以在前 l l l位随意求值(均可保证 b i < a i b_i<a_i bi<ai)使得前 l l l位均满足异或和相等的限制,而其余 n − 1 n-1 n−1个数字在前 l l l位的取值只需保证不超过 a a a序列即可,那么问题转化为求 n n n个数字在第 l l l位取值使得 b b b序列不超过 a a a序列且至少存在一个位置使得 b i < a i b_i<a_i bi<ai的方案数
以 d p [ i ] [ 1 / 0 ] [ 1 / 0 ] dp[i][1/0][1/0] dp[i][1/0][1/0]表示前 i i i个数字已经确定,他们在第 l l l位的异或和为 1 / 0 1/0 1/0,且前 i i i个数字中存在/不存在一个使得 b i < a i b_i<a_i bi<ai的位置的方案数,考虑转移
一.若 a i a_i ai在第 l l l位是 1 1 1,那么 b i b_i bi在第 l l l位有两种选择
1.
b
i
b_i
bi在第
l
l
l位取
0
0
0,假设
a
i
a_i
ai前
l
l
l位的取值为
x
x
x,那么只要
b
i
b_i
bi在前
l
l
l位的取值不超过
a
i
a_i
ai即可,有
x
+
1
x+1
x+1种方案,此时有转移
d
p
[
i
]
[
j
]
[
k
]
+
=
d
p
[
i
−
1
]
[
1
−
j
]
[
k
]
⋅
(
x
+
1
)
dp[i][j][k]+=dp[i-1][1-j][k]\cdot (x+1)
dp[i][j][k]+=dp[i−1][1−j][k]⋅(x+1)
2.
b
i
b_i
bi在第
l
l
l位取
0
0
0,那么前
l
l
l位
b
i
b_i
bi可以随意取,此时有转移
d
p
[
i
]
[
j
]
[
1
]
+
=
d
p
[
i
−
1
]
[
j
]
[
k
]
⋅
2
l
dp[i][j][1]+=dp[i-1][j][k]\cdot 2^l
dp[i][j][1]+=dp[i−1][j][k]⋅2l
二.若
a
i
a_i
ai在第
l
l
l位是
0
0
0,那么
b
i
b_i
bi在第
l
l
l位只能取
0
0
0,且较低位不能超过
a
i
a_i
ai,此时有转移
d
p
[
i
]
[
j
]
[
k
]
+
=
d
p
[
i
−
1
]
[
j
]
[
k
]
⋅
(
x
+
1
)
dp[i][j][k]+=dp[i-1][j][k]\cdot (x+1)
dp[i][j][k]+=dp[i−1][j][k]⋅(x+1)
那么对于当前考虑的位
l
l
l,对答案的贡献即为
d
p
[
n
]
[
r
e
s
]
[
1
]
2
l
\frac{dp[n][res][1]}{2^l}
2ldp[n][res][1],其中
r
e
s
res
res表示
a
i
a_i
ai在第
l
l
l位的异或和,除以
2
l
2^l
2l的原因是需要有一个严格小于
a
i
a_i
ai的
b
i
b_i
bi,在其他
n
−
1
n-1
n−1个数字在前
l
l
l位取值固定之后,
b
i
b_i
bi的前
l
l
l位需要做对应的取值使得前
l
l
l位的异或和也和
a
a
a序列相同
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;
}