【JZOJ6296】投票【期望概率】【dp】
题目大意:
题目链接:https://jzoj.net/senior/#main/show/6296
第个人有的概率会选择1,否则选择0。求在个人中选择个,1和0的个数相等的期望。
思路:
暴力搜索每一个人是不选,选1还是选0。用状压记录每一种选择方案的概率。
空间复杂度。
好像还可以拿。
代码
将排序,如果此时最有方案中存在一个选择的人,他左右均有人且都没有被选择,那么固定其他选择的人,在剩余的人中选择,期望一定为一个一次函数。所以这个人肯定王左或往右会更优。
所以设表示在中选择个人选择1,表示在中选择个人选择1。
以为例,如果这一个位置选择0,那么,如果这一个位置选择1,那么。
所以方程就是
最后枚举前面选多少人,以及前面几个人选1,计算一下答案即可。
时间复杂度
代码:
#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;
}