hdu 6595 (期望dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6595

对于一个全排列,每个逆序对可能出现的期望为 \(\frac{1}{2}\), 而全排列一共有 \(\frac{(n - 1)*n}{2}\) 个逆序对,
随机产生数列产生的期望为:

\[f[i] = \frac{i * (i - 1)}{4} + \sum_{j = 0}^{i}\frac{C_i^j * f[j]}{2^i} \]

移项得:

\[f[i] = \frac{\sum_{j = 0}^{i} C_i^j * f[j] + \frac{i * (i - 1)}{4}}{1 - \frac{1}{2^i}} \]

最终的答案即为:

\[ans = \frac{\sum_{i = 0}^{n}f[i]}{n} \]

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;

const int maxn = 3010;
const int M = 998244353;

int n;
int fac[maxn], ifac[maxn], po[maxn];
int inv2, inv4;
int f[maxn];

int qsm(int i, int po){
	int res = 1;
	while(po){
		if(po & 1) res = 1ll * res * i % M;
		po >>= 1;
		i = 1ll * i * i % M;
	}
	return res;
}

int C(int x, int y){ return 1ll * fac[x] * ifac[y] % M * ifac[x - y] % M; }

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	fac[0] = 1;
	for(int i = 1 ; i <= 3000 ; ++i) fac[i] = 1ll * fac[i - 1] * i % M;
	ifac[3000] = qsm(fac[3000], M - 2);
	for(int i = 2999 ; i >= 0 ; --i) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % M;	
	po[0] = 1;
	inv2 = qsm(2, M - 2);
	inv4 = qsm(4, M - 2);
	for(int i = 1 ; i <= 3000 ; ++i) po[i] = 1ll * po[i - 1] * inv2 % M;
	
	f[0] = 0;
	f[1] = 0;
	for(int i = 2 ; i <= 3000 ; ++i){
		f[i] = 1ll * (i - 1) * i % M * inv4 % M;
		for(int j = 0 ; j < i ; ++j){
			f[i] = (f[i] + 1ll * C(i, j) * f[j] % M * po[i] % M) % M;
		}
		f[i] = 1ll * f[i] * qsm((1 - po[i] + M) % M, M - 2) % M;
	}
	
	while(scanf("%d", &n) != EOF){
		int ans = 0;
		for(int i = 0 ; i <= n ; ++i) ans = (ans + 1ll * f[i] * qsm(n, M - 2) % M) % M;
		printf("%d\n", ans);
	}

	return 0;
}
posted @ 2020-12-20 21:13  Tartarus_li  阅读(67)  评论(0编辑  收藏  举报