Topcoder RandomPaintingOnABoard(min-max容斥)

Topcoder RandomPaintingOnABoard(min-max容斥)

题目大意

给定一个 \(n * m\) 的矩阵,每个元素是 \(0 \to9\) 的数字,每次以 \(\frac {p[i][j]}{sum}\) 的概率将第 i 块染黑(每次染一个块),想让每行每列都有至少一个块被染色,求期望次数

数据范围

\(n * m \le 200, p[i][j] \le 9\)

解题思路

\(min-max\) 容斥将最后一个被染色转化成第一个被染色,我们有

\[\max(S)=\sum_{T \subset S}(-1)^{|T|+1}\min(T) \\ =\sum_{T \subset S}(-1)^{|T|+1}\sum_{i=0}P(i)*i\\ =\sum_{T \subset S}(-1)^{|T|+1}\sum_{i=0}P(x \ge i)\\ =\sum_{T \subset S}(-1)^{|T|+1}\sum_{i=0}(1-\frac {sum(T)}{Sum})^i\\ =\sum_{T \subset S}(-1)^{|T|+1}\frac {Sum}{sum(T)}\\ \]

好了可以愉快的 dp 了,假设 \(n \le m\),显然可以暴力枚举 n,然后套路的 dp 即可

代码奉上

#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template<typename F>
inline void write(F x, char ed = '\n')
{
	static short st[30];short tp=0;
	if(x<0) putchar('-'),x=-x;
	do st[++tp]=x%10,x/=10; while(x);
	while(tp) putchar('0'|st[tp--]);
	putchar(ed);
}

template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }

template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }


const int N = 205;
const int P = 998244353;
#define LD long double
ll p[N][N], bs[N], sum;
LD f[N][N*9]; ll m, n;
char s[N];

class RandomPaintingOnABoard{
public:
	LD expectedSteps(const vector<string> &prob) {
		n = prob.size(), m = prob[0].size();
		for (int i = 1;i <= n; i++) {
			for (int j = 1;j <= m; j++)
				if (n < m) p[i][j] = prob[i-1][j-1] - '0', sum += p[i][j];
				else p[j][i] = prob[i-1][j-1] - '0', sum += p[j][i];
		}
		if (n > m) swap(n, m);
		LD ans = 0;
		int all = (1 << n) - 1;
		for (int i = 0;i <= all; i++) {
			ll sz = 0, res = 0;
			for (int j = 1;j <= n; j++) {
				if (i & (1 << (j - 1))) {
					bs[j] = 1, sz++;
					for (int k = 1;k <= m; k++) 
						res += p[j][k];
				}
				else bs[j] = 0;
			}
			memset(f, 0, sizeof(f)); f[0][res] = 1;		
			for (int j = 1;j <= m; j++) {
				int tp = 0;
				for (int k = 1;k <= n; k++)
					if (!bs[k]) tp += p[k][j];
				for (int k = 0;k <= res; k++)
					f[j][k + tp] -= f[j-1][k], f[j][k] += f[j-1][k];
				res += tp;
			}
			for (int k = 1;k <= res; k++) {
				if (sz & 1) ans += f[m][k] * sum / k;
				else ans -= f[m][k] * sum / k;
			}
//			printf ("%.10Lf\n", ans);
		}
		return ans;
	}
};

//int main(){
//	vector<string> prob=
//	{"000000000000001000000",
//	 "888999988889890999988",
//	 "980016505602315105399",
//	 "889898998889980999898",
//	 "988812312398988089999",
//	 "998888991151513889998",
//	 "998988999898990889899",
//	 "135135489465125616545",
//	 "958646813213300035186"};
//	RandomPaintingOnABoard tmp;
//	LD ans=tmp.expectedSteps(prob);
//	printf("%.10Lf\n",ans);
//	return 0;
//}


posted @ 2020-07-14 19:59  Hs-black  阅读(114)  评论(0编辑  收藏  举报