Parity of Tuples (Easy)
题意:
输入
n
(
1
e
4
)
,
m
(
10
)
,
k
(
30
)
n(1e4),m(10),k(30)
n(1e4),m(10),k(30)
接下来
n
n
n行,第
i
i
i行输入
a
i
1
,
a
i
2
,
…
,
a
i
m
(
0
≤
a
i
j
<
2
k
)
a_{i1},a_{i2},\dots,a_{im}(0\leq a_{ij}<2^k)
ai1,ai2,…,aim(0≤aij<2k)
求
∑
x
=
0
2
k
−
1
c
o
u
n
t
(
x
)
3
x
m
o
d
1
0
9
+
7
\sum_{x=0}^{2^k-1}count(x)3^x\mod10^9+7
∑x=02k−1count(x)3xmod109+7
其中
c
o
u
n
t
(
x
)
count(x)
count(x)表示
i
i
i的个数,对于任意的
1
≤
j
≤
m
1\leq j\leq m
1≤j≤m使
a
i
j
&
x
a_{ij}\&x
aij&x中位为1的个数为奇数。
题解:
显然可以分析出,不同的
i
i
i,(即不同的行),它的贡献是相互独立的。于是便对每一行算贡献。
而对于每一行,肯定要从位的角度考虑问题,于是就引入状压
d
p
dp
dp
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示
0
,
1
,
…
,
i
−
1
0,1,\dots,i-1
0,1,…,i−1位,状态为
j
j
j(位为1表示奇数),的贡献。
转移:
d
p
[
i
]
[
j
]
=
d
p
[
i
]
[
j
]
+
d
p
[
i
−
1
]
[
j
]
dp[i][j]=dp[i][j]+dp[i-1][j]
dp[i][j]=dp[i][j]+dp[i−1][j]不算该位贡献;
d
p
[
i
]
[
j
]
=
d
p
[
i
]
[
j
]
+
d
p
[
i
−
1
]
[
j
⨁
s
t
]
×
3
2
i
−
1
dp[i][j]=dp[i][j]+dp[i-1][j\bigoplus st]\times3^{2^{i-1}}
dp[i][j]=dp[i][j]+dp[i−1][j⨁st]×32i−1算该位的贡献。
最后返回
d
p
[
k
]
[
2
m
−
1
]
dp[k][2^m-1]
dp[k][2m−1]
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,m,k,a[19];
int dp[34][1<<11];
int base[39];
int solve(){
for(int i=1;i<=m;i++)cin>>a[i];
for(int i=0;i<=k;i++)for(int j=0;j<(1<<m);j++)dp[i][j]=0;
dp[0][0]=1;
for(int i=1;i<=k;i++){
int zt=0;
for(int j=1;j<=m;j++)if(a[j]&(1<<(i-1)))zt|=(1<<j-1);
for(int j=0;j<(1<<m);j++){
dp[i][j]=(dp[i][j]+dp[i-1][j])%mod;
dp[i][j]=(dp[i][j]+1ll*dp[i-1][j^zt]*base[i-1])%mod;
}
}
return dp[k][(1<<m)-1];
}
int main(){
//freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
base[0]=3;
for(int i=1;i<=31;i++)base[i]=1ll*base[i-1]*base[i-1]%mod;
while(cin>>n>>m>>k){
int ans=0;
while(n--)ans=(ans+solve())%mod;
cout<<ans<<endl;
}
return 0;
}