您的位置:首页 > 其它

BZOJ 2720 浅谈期望线性性分部转移

2017-09-18 16:32 246 查看


世界真的很大

(纪念Re:CREATORS完结!!)

期望是个很神奇的东西

明确题意的期望思路之后,考虑怎么把期望的步骤分开一降低时间复杂度

写出来之后考虑每一次转移之间的关系,进一步优化代码

最后是O(n^2)的,应该是有O(n)做法的,应该改为巧妙

看题先:

description



input



output



首先这道题求的是距离总和的期望。

由于直接枚举排列再去暴力统计是不太可能的

期望即权值 * 概率,考虑分开来考虑,枚举每个小盆友的距离,算出当前情况下的概率,乘上累加就是答案

假设枚举到第8个小盆友,枚举其距离为6,我们要算出来的就是出现这种情况的概率

而出现这种情况,就是说,第8个小盆友的前面5个人都要比他矮,而第6个人恰恰比他高,我们要算出来的就是这个

设有tot个人的身高比第8个小盆友矮,有sum个小盆友比这个小盆友的身高高

这个小盆友的前面第一个人比他矮的概率本来是 tot/(n-1),但是由于要考虑老师的存在,假设老师无限高,那么总人数就会增加,但是tot却不会增加,所以概率是tot/n

再往前一个小盆友比他矮的概率,由于已经用掉了两个小盆友(第8个和前面的那个),其概率就是(tot-1)/(n-2+1),以此类推

一直到那一个比他高的小盆友,这时已经用掉了6个小盆友了,这个小盆友比他高的概率就是(sum+1)/(tot-6+1),sun+1是由于考虑了老师的缘故,这样就得出了一种n^3的做法

完整代码:

#include<stdio.h>

const int INF=0x3f3f3f3f;

int n,h[100010],sum[100010],tot[100010];
double ans=0;

int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&h[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
sum[i]+=(h[j]>=h[i]),tot[i]+=(h[j]<h[i]);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=tot[i]+1;j++)
{
double p=1;
for(int k=1;k<j;k++)
p*=(double) (tot[i]-k+1)/(n-k+1);
if(n>j)
p*=(double) (sum[i]+1)/(n-j+1);
ans+=p*j;
}
}
printf("%0.2lf\n",ans);
return 0;
}
/*
EL PSY CONGROO
*/


考虑每一次枚举距离的时候,这一步的距离是比上一步+1的,只是比上一步多乘了一个东西而已

这样我们就发现,可以用递推来处理,优化到n^2

完整代码:

#include<stdio.h>

const int INF=0x3f3f3f3f;

int n,h[100010],sum[100010],tot[100010];
double ans=0;

int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&h[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
sum[i]+=(h[j]>=h[i]),tot[i]+=(h[j]<h[i]);
for(int i=1;i<=n;i++)
{
double p=1;
for(int j=1;j<=tot[i]+1;j++)
{
if(n==j) ans+=p*j;
else ans+=p*(double) (sum[i]+1)/(n-j+1)*j;
p*=double (tot[i]-j+1)/(n-j+1);
}
}
printf("%0.2lf\n",ans);
return 0;
}
/*
EL PSY CONGROO
*/


嗯,就是这样
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: