题目大意:
给你n个含m个元素的向量 a 1 , a 2 , . . , a n a_1,a_2,..,a_n a1,a2,..,an,对于一个给定的k,求 ∑ x = 0 2 k − 1 c o u n t ( x ) ⋅ 3 x \sum_{x = 0}^{2^k - 1} \mathrm{count}(x) \cdot 3^x ∑x=02k−1count(x)⋅3x modulo ( 1 0 9 + 7 ) (10^9+7) (109+7),其中count(x)是满足对(1<=j<=m)x& a i , j a_{i,j} ai,j中1的数目为奇数的向量个数。
解题思路:
我们发现可以对于每个向量单独算贡献,那么问题就转换成对于一个包含最多10个元素的向量,求
∑
x
=
0
2
k
−
1
3
x
\sum_{x = 0}^{2^k - 1} 3^x
∑x=02k−13x modulo
(
1
0
9
+
7
)
(10^9+7)
(109+7),其中x需要满足和每个元素的与的1的个数为奇数。那么我们把x二进制拆分后可以算
3
2
0
,
3
2
1
,
3
2
2
,
.
.
3
2
k
−
1
3^{2^0},3^{2^1},3^{2^2},..3^{2^{k-1}}
320,321,322,..32k−1的贡献。我们从低位到高位考虑,用mask来代表每种元素奇偶性,第i位为1代表第i个元素的1的个数为奇数,设
d
p
[
i
]
[
m
a
s
k
]
dp[i][mask]
dp[i][mask]表示0到i-1位中,每个元素的1的个数奇偶性为mask的时候的贡献,那么x的第i位取0和取1可以分别转移到dp[i+1][mask]和dp[i+1][mask ^ amask],其中amask代表第i位为1的元素的集合,第i位取1会改变这些元素的1的个数的奇偶性。
最后dp[k][(1<<m)-1]就是前k位1的个数全是奇数的总贡献。把所有向量的贡献加起来就是答案。
#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const ll mod = 1e9 + 7;
ll dp[31][1<<11];
int a[12], m , k;
ll bin[33];
ll sol(){
for(int i = 0; i <= k; ++i) for(int j = 0; j < (1<<m); ++j) dp[i][j] = 0;
for(int i = 0; i < m; ++i) scanf("%d", &a[i]);
dp[0][0] = 1;
for(int i = 0; i < k; ++i){
int amask = 0;
for(int j = 0; j < m; ++j) if((a[j]>>i)&1) amask |= (1<<j);
for(int mask = 0; mask < (1<<m); ++mask){
dp[i+1][mask] = (dp[i+1][mask] + dp[i][mask])%mod;
dp[i+1][mask^amask] = (dp[i+1][mask^amask] + bin[i]*dp[i][mask])%mod;
}
}
return dp[k][(1<<m)-1];
}
int main()
{
bin[0] = 3; for(int i = 1; i < 33; ++i) bin[i] = bin[i-1]*bin[i-1]%mod;
int n;
while(scanf("%d%d%d", &n, &m, &k)!=EOF){
ll ans = 0;
while (n--) ans =(ans + sol())%mod;
printf("%lld\n", ans);
}
}