1117考试T4

1117考试总结T4

​ 题目大意:

​ 锦标赛游戏的规则是这样的:一共有 i(1≤i≤n)个人参与游戏,每个人都编上号(之后用 编号代替人)。任意两个人之间都要进行一场比赛(即单循环赛制),每一场比赛双方获胜的 概率都是 0.5。对于两个人 x 和 y(1≤x,y≤i),如果 x=y 或存在一个序列(a 1 ,a 2 ,...,a m )(m≥2),满足 a 1 战胜了 a 2 ,a 2 战胜了 a 3 ,...,a m-1 战胜了 a m ,且 a 1 =x,a m =y,则称 x 不弱于 y。如果 x 不弱于 y 且 y 不弱于 x,则称 x 和 y 是实力相当的。比赛结束后会给每个人发奖金。如果某个人 j(1≤j≤i)有 k(1≤k≤n)个人和他实力相当,则给他发 \(d_k\) 元奖金。奖金最多的人获胜。
​ 算出对于每一个 i,所有编号的期望奖金的最大值是多少。这个数字可能不是有限小数,所以你需要求的是答案 mod 998244353的结果。\(n <= 3000\)

​ DP + 期望 + 图论知识.

​ 首先我们知道这可以连成一张完全图, 因为每两个人之间都要进行一场比赛.又因为比赛有正有负, 并且概率是0.5, 所以我们可以等概率的给每条边标上正反两个方向, 形成了一个有向完全图, 也叫作竞赛图.会等概率的形成\(\displaystyle 2 ^ { \frac{n(n - 1)}{2}}\)个竞赛图.

​ 我们又可以发现, 每个人的期望得分是相同的.所以答案可以这么算:总价值/情况总数.

\(a_i\)表示"这个图是一个强联通分量并且这个图包含\(i\)个点"这种图的个数, 然后我们可以列出一个等式:

\(\displaystyle 2^{\frac{n(n - 1)}{2}} = \sum_{i = 1}^{n}C_n^ia_i2^{\frac{(n - i)(n - i - 1)}{2}}\).

​ 等式右边解释一下:\(i\)枚举的是这个\(n\)个点的竞赛图缩点后, \(topo\)排序后剩下的最后一个点的大小,(这个点是由几个强联通点缩点后形成的).然后我们从\(i\)个点中任选\(i\)个点作为最后的这个点, 剩下\(n - i\)个点随便连边.那么枚举的这\(i\)个点与剩下\(n - i\)个点之间的那些边为什么没有考虑呢?因为根据\(i\)的定义, 这\(i\)个点肯定是最后剩下的那些点, 缩点后是不能有出边的, 否则它将不是最后剩下的那个点, 所以说中间的那些边是已经确定方向的, 不用考虑.

​ 我们把上式的\(a_n\)提到等式的一边:\(a_n = \displaystyle 2^{\frac{n(n - 1)}{2}} - \sum_{i = 1}^{n - 1}C_n^ia_i2^{\frac{(n - i)(n - i - 1)}{2}}\),然后我们就可以\(O(n ^ 2)\)的计算\(a\)数组了.

​ 为什么要计算\(a\)数组呢?因为我们要计算\(f\)数组.

\(f_i\)表示有\(i\)个人参与游戏时的总价值是多少, 然后我们可以写出:

\(f_n = \displaystyle \sum_{i = 1}^{n} C_n^ia_i(f_{n - i} + i*d_i * 2^{\frac{(n - i)(n - i - 1)}{2}})\).

​ 等式右边解释一下:\(i\)的含义和上面一样, 也是这个\(n\)个点的竞赛图缩点后, \(topo\)排序后最后剩下的那个点的大小.还是从\(n\)个点里面任选\(i\)个.然后还剩下\(n - i\)个点, 这\(n - i\)个点随便连边的情况数乘上每一种情况都将有\(i\)个人每人拿到\(d_i\)元奖金.

​ 最后的答案就是:\(\displaystyle ans_i = \frac{f_i}{2^{\frac{i(i - 1)}{2}} *i}\).(就是上面那个总价值/情况总数, 另外还要把总价镇平分到每个人身上, 也就是在除\(i\)).

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

const int N = 3005, mod = 998244353;
int n;
int d[N], a[N], f[N], C[N][N], pow_2[N * N];

void make_pre() {
	pow_2[0] = 1;
	for(int i = 1;i < N * N; i++) pow_2[i] = 1ll * pow_2[i - 1] * 2 % mod;
	for(int i = 0;i < N; i++) C[i][0] = 1;
	for(int i = 1;i < N; i++) 
		for(int j = 1;j < N; j++) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}

int ksm(long long x, int y) {
	int res = 1;
	while(y) { if(y & 1) res = 1ll * res * x % mod; x = x * x % mod; y >>= 1; };
	return res;
}

int main() {

	n = read(); make_pre();
	for(int i = 1;i <= n; i++) d[i] = read();
	for(int i = 1;i <= n; i++) {
		a[i] = pow_2[i * (i - 1) / 2];
		for(int j = 1;j <= i - 1; j++) 
			a[i] = ((a[i] - 1ll * pow_2[(i - j) * (i - j - 1) / 2] * C[i][j] % mod * a[j] % mod) % mod + mod) % mod;			
	}
	for(int i = 1;i <= n; i++) 
		for(int j = 1;j <= i; j++)
			f[i] = (f[i] + 1ll * C[i][j] * a[j] % mod * ((f[i - j] + 1ll * j * d[j] % mod * pow_2[(i - j) * (i - j - 1) / 2] % mod) % mod) % mod) % mod;
	for(int i = 1;i <= n; i++) 
		printf("%lld\n", 1ll * ksm(1ll * i * pow_2[i * (i - 1) / 2] % mod, mod - 2) * f[i] % mod);
	
	return 0;
}
posted @ 2020-11-18 06:47  C锥  阅读(99)  评论(0编辑  收藏  举报