注意到
m
m
比较小,不妨状压。
我们设
fi,j,S
f
i
,
j
,
S
表示
Ai
A
i
用掉集合
S
S
中的操作后值为的概率。
再设
gi,j,S
g
i
,
j
,
S
表示
A1..i
A
1..
i
用掉集合
S
S
中的操作后最大值为的概率,枚举
Ai
A
i
使用的操作集合转移即可。
复杂度
O(nc2m23m)
O
(
n
c
2
m
2
3
m
)
。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define up(x,y) (x=(x+(y))%mod)
#define in(x,s) ((s>>(x-1))&1)
#define ll long long
using namespace std;
const int mod=1000000007;
int n,m,c,pc[1030];
ll P[41][11][4],f[41][31][1030],g[41][31][1030],ans;
int main()
{
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
for(int k=0;k<=c;k++)
scanf("%lld",&P[j][i][k]);
for(int s=0;s<(1<<m);s++)
for(int t=s;t;t>>=1) pc[s]+=(t&1);
for(int i=1;i<=n;i++)
{
f[i][0][0]=1;
for(int j=1;j<=m;j++)
for(int s=0;s<(1<<(j-1));s++)
for(int k=0;k<=c*(j-1);k++)
if(f[i][k][s])
for(int l=0;l<=c;l++)
up(f[i][k+l][s|(1<<(j-1))],f[i][k][s]*P[i][j][l]);
}
g[0][0][0]=1;
for(int i=1;i<=n;i++)
for(int s=0;s<(1<<m);s++)
for(int j=0;j<=pc[s]*c;j++)
if(g[i-1][j][s])
for(int u=((1<<m)-1)^s,t=u;;t=(t-1)&u)
{
for(int k=0;k<=pc[u]*c;k++)
up(g[i][max(j,k)][s+t],g[i-1][j][s]*f[i][k][t]);
if(!t) break;
}
for(int i=0;i<=c*m;i++)
up(ans,g[n][i][(1<<m)-1]*i%mod);
printf("%lld",ans);
return 0;
}