【JZOJ6296】投票【期望概率】【dp】

题目大意:

题目链接:https://jzoj.net/senior/#main/show/6296
ii个人有pip_i的概率会选择1,否则选择0。求在nn个人中选择mm个,1和0的个数相等的期望。


思路:

30pts30pts

O(3n)O(3^n)暴力搜索每一个人是不选,选1还是选0。用状压记录每一种选择方案的概率。
空间复杂度O(2n)O(2^n)
好像O(4n)O(4^n)还可以拿40pts40pts
代码LinkLink


100pts100pts

pip_i排序,如果此时最有方案中存在一个选择的人,他左右均有人且都没有被选择,那么固定其他选择的人,在剩余的人中选择,期望一定为一个一次函数。所以这个人肯定王左或往右会更优。
所以设f[i][j]f[i][j]表示在[1,i][1,i]中选择jj个人选择1,g[i][j]g[i][j]表示在[i,n][i,n]中选择jj个人选择1。
ff为例,如果这一个位置选择0,那么f[i][j]=f[i1][j1]×(1p[i])f[i][j]=f[i-1][j-1]\times (1-p[i]),如果这一个位置选择1,那么f[i][j]=f[i1][j1]×p[i]f[i][j]=f[i-1][j-1]\times p[i]
所以方程就是
f[i][j]=f[i1][j]×(1p[i])+f[i1][j1]×p[i]f[i][j]=f[i-1][j]\times (1-p[i])+f[i-1][j-1]\times p[i]
最后枚举前面选多少人,以及前面几个人选1,计算一下答案即可。
时间复杂度O(nm)O(nm)


代码:

#include <cstdio>
#include <algorithm>
using namespace std;

const int N=2010;
double p[N],f[N][N],g[N][N],ans,maxn;
int n,m;

int main()
{
	freopen("vote.in","r",stdin);
	freopen("vote.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%lf",&p[i]);
	sort(p+1,p+1+n);
	f[0][0]=g[n+1][0]=1.0;
	for (int i=1;i<=n;i++)
		for (int j=0;j<=m;j++)
		{
			if (!j) f[i][j]=f[i-1][j]*(1-p[i]);
			f[i][j]=f[i-1][j]*(1-p[i])+f[i-1][j-1]*p[i];
		}
	for (int i=n;i>=1;i--)
		for (int j=0;j<=m;j++)
		{
			if (!j) g[i][j]=g[i+1][j]*(1-p[i]);
			g[i][j]=g[i+1][j]*(1-p[i])+g[i+1][j-1]*p[i];
		}
	for (int i=0;i<=m;i++)
	{
		ans=0.0;
		for (int j=0;j<=m/2;j++)
			ans+=f[i][j]*g[n-m+i+1][m/2-j];
		if (ans>maxn) maxn=ans;
	}
	printf("%0.8lf",maxn);
	return 0;
}
posted @ 2019-08-15 16:43  全OI最菜  阅读(161)  评论(0编辑  收藏  举报