题解 Max
部分分很有启发性
令 \(f_{i, s, j}\) 为到位置 \(i\),最大值为 \(j\),已用操作集合为 \(s\) 概率和
令 \(g_{i, s, j}\) 为到位置 \(i\),使用 \(s\) 中操作,和为 \(j\) 的方案概率和
那么 f 就可以转移了
复杂度 \(O(n3^mm^2c^2)\),不知道为什么可以过
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m, c;
ll p[12][42][5];
const ll mod=1e9+7;
inline void add(ll& a, ll b) {a=(a+b)%mod;}
namespace force{
ll ans=0;
int a[N];
void dfs(int u, ll pre) {
if (u>m) {
int maxn=0;
for (int i=1; i<=n; ++i) maxn=max(maxn, a[i]);
ans=(ans+pre*maxn)%mod;
return ;
}
for (int i=1; i<=n; ++i) {
for (int j=0; j<=c; ++j) {
a[i]+=j;
dfs(u+1, pre*p[u][i][j]%mod);
a[i]-=j;
}
}
}
void solve() {
dfs(1, 1);
printf("%lld\n", (ans%mod+mod)%mod);
}
}
namespace task1{
ll f[42][1<<10][32], pre[42][1<<10], ans;
void solve() {
// cout<<double(sizeof(f))/1000/1000<<endl;
f[1][0][0]=1;
int lim=1<<m, up=m*c;
for (int i=1; i<=n; ++i) {
for (int s=0; s<lim; ++s) {
pre[i][s]=1;
for (int j=1; j<=m; ++j) if (s&(1<<(j-1))) {
pre[i][s]=pre[i][s]*p[j][i][1]%mod;
}
}
}
for (int i=1; i<=n; ++i) {
for (int s=0; s<lim; ++s) {
for (int j=0; j<=up; ++j) if (f[i][s][j]) {
for (int t=(~s)&(lim-1),t0=t; ; t0=t&(t0-1)) {
// assert((s&t0)==0);
add(f[i+1][s|t0][max(j, __builtin_popcount(t0))], f[i][s][j]*pre[i][t0]);
if (!t0) break;
}
}
}
}
for (int i=1; i<=up; ++i) ans=(ans+i*f[n+1][lim-1][i])%mod;
printf("%lld\n", (ans%mod+mod)%mod);
}
}
namespace task2{
ll f[42][1<<10][32], g[42][1<<10][32], t[13][32], ans;
void solve() {
f[1][0][0]=1;
// cout<<double(sizeof(f)+sizeof(g))/1000/1000<<endl;
int lim=1<<m, up=m*c;
for (int i=1; i<=n; ++i) {
for (int s=0; s<lim; ++s) {
memset(t, 0, sizeof(t));
t[1][0]=1;
for (int j=1; j<=m; ++j) {
if (s&(1<<(j-1))) {
for (int l=0; l<=c; ++l)
for (int k=0; k+l<=up; ++k)
add(t[j+1][k+l], t[j][k]*p[j][i][l]);
}
else {
for (int k=0; k<=up; ++k) t[j+1][k]=t[j][k];
}
}
for (int j=0; j<=up; ++j) g[i][s][j]=t[m+1][j];
}
}
for (int i=1; i<=n; ++i) {
for (int s=0; s<lim; ++s) {
for (int j=0; j<=up; ++j) if (f[i][s][j]) {
for (int t=(~s)&(lim-1),t0=t; ; t0=t&(t0-1)) {
for (int k=0; k<=up; ++k) if (g[i][t0][k])
add(f[i+1][s|t0][max(j, k)], f[i][s][j]*g[i][t0][k]);
if (!t0) break;
}
}
}
}
for (int i=1; i<=up; ++i) ans=(ans+i*f[n+1][lim-1][i])%mod;
printf("%lld\n", (ans%mod+mod)%mod);
}
}
signed main()
{
freopen("max.in", "r", stdin);
freopen("max.out", "w", stdout);
n=read(); m=read(); c=read();
for (int i=1; i<=m; ++i) for (int j=1; j<=n; ++j) for (int k=0; k<=c; ++k) p[i][j][k]=read();
// force::solve();
// task1::solve();
task2::solve();
return 0;
}