题解 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;
}
posted @ 2022-04-03 21:12  Administrator-09  阅读(1)  评论(0编辑  收藏  举报