题目链接
题目解法
考虑异或的性质,一个数被异或偶数次相当于
0
0
0,一个数被异或奇数次相当于只异或一次
考虑每个数若出现了
b
1
,
b
2
,
.
.
.
,
b
n
b_1,b_2,...,b_n
b1,b2,...,bn 次,其中
b
1
+
b
2
+
.
.
.
+
b
n
=
k
b_1+b_2+...+b_n=k
b1+b2+...+bn=k
那么这种情况出现的次数为
(
n
b
1
)
∗
(
n
−
b
1
b
2
)
∗
.
.
.
∗
(
n
−
b
1
−
b
2
−
.
.
.
−
b
n
−
1
b
n
)
(^{b_1}_{n})*(^{b_2}_{n-b_1})*...*(^{b_n}_{n-b_1-b_2-...-b_{n-1}})
(nb1)∗(n−b1b2)∗...∗(n−b1−b2−...−bn−1bn)
如果次数需要为偶数,那么根据
l
u
c
a
s
lucas
lucas 定理,
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an 都必须是
k
k
k 二进制表示的子集
这把问题转化为了对于每个
k
k
k 的二进制位,都可以填上
a
1
,
a
2
,
.
.
,
a
n
a_1,a_2,..,a_n
a1,a2,..,an,求每种方案的数和的异或和
考虑数位
d
p
dp
dp,令
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示到第
i
i
i 位时,前面的进位+当前加上的
a
i
a_i
ai 为
j
j
j 的方案数
- k k k 的第 i i i 位为 0, d p [ i ] [ j / 2 ] − > d p [ i − 1 ] [ j ] dp[i][j/2] \;->\;dp[i-1][j] dp[i][j/2]−>dp[i−1][j]
- k k k 的第 i i i 位为 1, d p [ i − 1 ] [ j ] − > d p [ i ] [ j / 2 + a i ] dp[i-1][j]\;->\;dp[i][j/2+a_i] dp[i−1][j]−>dp[i][j/2+ai]
最后统计答案的时候需要后面总的方案数与当前方案数的乘积为奇数,且 j j j 为奇数,答案才能异或上 2 i 2^i 2i
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N(1100);
int n,k,ans,a[N];
bool dp[55][N<<1];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void calc(int p){
int ways=1;
for(int i=p+1;i<=51;i++) if(k>>(i-1)&1) ways=ways*n%2;
if(!ways) return;
for(int i=1;i<N<<1;i+=2) if(dp[p][i]) ans^=1ll<<(p-1);
}
signed main(){
n=read(),k=read();
for(int i=1;i<=n;i++) a[i]=read();
dp[0][0]=1;
for(int i=1;i<=51;i++){
if(k>>(i-1)&1) for(int j=0;j<N<<1;j++) for(int l=1;l<=n;l++) dp[i][j/2+a[l]]^=dp[i-1][j];
else for(int j=0;j<N<<1;j++) dp[i][j/2]^=dp[i-1][j];
calc(i);
// cout<<ans<<'\n';
}
printf("%lld",ans);
return 0;
}
//dp[i][j]:到第i位当前位的和为j的方案数 %2 的值