@y20070316
2017-02-13T06:21:45.000000Z
字数 2560
阅读 933
OI
个人,比赛轮。
对于每一轮,一个人的分数为它的排名。一个人的总的分数为每局分数之和。
给定某个人第轮的排名,求它的总分的期望排名。
总分的期望排名,就是
什么是一个人对他的贡献?
我们设一个人的排名比他低,贡献为,排名比他高,贡献为。
所以:
只需要求出一个人比他排名低的概率即可。
设某个人的分数为。
设表示轮下来分数为的概率,则
奠基:
转移:
前缀和进行优化dp。
#include <cstdio>#include <cstring>#include <cctype>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define LD long doubleint rd(void);const int N=128;const int A=100005;int n,m;int rk[N];int sum;int scr;LD f[2][A];LD s[2][A];LD ans;int main(void) {#ifndef ONLINE_JUDGEfreopen("A.in","r",stdin);freopen("A.out","w",stdout);#endifn=rd(),m=rd();F(i,1,n)rk[i]=rd();F(i,1,n)sum+=rk[i];scr=n*m;f[0][0]=1;F(j,0,scr)s[0][j]=1;F(i,1,n) {int nb=(i&1);int rb=(nb^1);memset(f[nb],0,sizeof f[nb]);memset(s[nb],0,sizeof s[nb]);F(j,i*1,i*m) {int l=j-m;l=max(l,0);int r=j-1;if (l>r)continue;f[nb][j]=s[rb][r]-(l==0?0:s[rb][l-1]);if (l<=j-rk[i]&&j-rk[i]<=r)f[nb][j]-=f[rb][j-rk[i]];f[nb][j]/=(m-1);}s[nb][0]=f[nb][0];F(j,1,scr)s[nb][j]=s[nb][j-1]+f[nb][j];}int nb=(n&1);F(i,1,sum-1)ans+=f[nb][i];ans*=(m-1);printf("%0.15Lf\n",ans+1);return 0;}int rd(void) {int x=0,f=1; char c=getchar();while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}while (isdigit(c)) {x=x*10+c-'0';c=getchar();}return x*f;}
自己YY出来的方法。
单点修改。
子树查询。
#include <cstdio>#include <cstring>#include <cctype>#include <algorithm>using namespace std;#define F(i,a,b) for (int i=(a);i<=(b);i++)#define LD long doubleint rd(void);const int N=128;const int A=100005;int n,m;int rk[N];int sum;int scr;LD f[2][A];LD s[2][A];LD ans;int main(void) {#ifndef ONLINE_JUDGEfreopen("A.in","r",stdin);freopen("A.out","w",stdout);#endifn=rd(),m=rd();F(i,1,n)rk[i]=rd();F(i,1,n)sum+=rk[i];scr=n*m;f[0][0]=1;F(j,0,scr)s[0][j]=1;F(i,1,n) {int nb=(i&1);int rb=(nb^1);memset(f[nb],0,sizeof f[nb]);memset(s[nb],0,sizeof s[nb]);F(j,i*1,i*m) {int l=j-m;l=max(l,0);int r=j-1;if (l>r)continue;f[nb][j]=s[rb][r]-(l==0?0:s[rb][l-1]);if (l<=j-rk[i]&&j-rk[i]<=r)f[nb][j]-=f[rb][j-rk[i]];f[nb][j]/=(m-1);}s[nb][0]=f[nb][0];F(j,1,scr)s[nb][j]=s[nb][j-1]+f[nb][j];}int nb=(n&1);F(i,1,sum-1)ans+=f[nb][i];ans*=(m-1);printf("%0.15Lf\n",ans+1);return 0;}int rd(void) {int x=0,f=1; char c=getchar();while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}while (isdigit(c)) {x=x*10+c-'0';c=getchar();}return x*f;}
路径修改。
单点查询。
更简单。
简单得多。。