[关闭]
@y20070316 2017-02-13T06:21:45.000000Z 字数 2560 阅读 933

NOIP2016模拟赛三十

OI


【xsy1803】rank - 概率dp

题意

个人,比赛轮。
对于每一轮,一个人的分数为它的排名。一个人的总的分数为每局分数之和。
给定某个人第轮的排名,求它的总分的期望排名。

分析

总分的期望排名,就是

什么是一个人对他的贡献?
我们设一个人的排名比他低,贡献为,排名比他高,贡献为

所以:

只需要求出一个人比他排名低的概率即可。

设某个人的分数为

表示轮下来分数为的概率,则


考虑如何求

奠基:
转移:

前缀和进行优化dp。

代码

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cctype>
  4. #include <algorithm>
  5. using namespace std;
  6. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  7. #define LD long double
  8. int rd(void);
  9. const int N=128;
  10. const int A=100005;
  11. int n,m;
  12. int rk[N];
  13. int sum;
  14. int scr;
  15. LD f[2][A];
  16. LD s[2][A];
  17. LD ans;
  18. int main(void) {
  19. #ifndef ONLINE_JUDGE
  20. freopen("A.in","r",stdin);
  21. freopen("A.out","w",stdout);
  22. #endif
  23. n=rd(),m=rd();
  24. F(i,1,n)
  25. rk[i]=rd();
  26. F(i,1,n)
  27. sum+=rk[i];
  28. scr=n*m;
  29. f[0][0]=1;
  30. F(j,0,scr)
  31. s[0][j]=1;
  32. F(i,1,n) {
  33. int nb=(i&1);
  34. int rb=(nb^1);
  35. memset(f[nb],0,sizeof f[nb]);
  36. memset(s[nb],0,sizeof s[nb]);
  37. F(j,i*1,i*m) {
  38. int l=j-m;
  39. l=max(l,0);
  40. int r=j-1;
  41. if (l>r)
  42. continue;
  43. f[nb][j]=s[rb][r]-(l==0?0:s[rb][l-1]);
  44. if (l<=j-rk[i]&&j-rk[i]<=r)
  45. f[nb][j]-=f[rb][j-rk[i]];
  46. f[nb][j]/=(m-1);
  47. }
  48. s[nb][0]=f[nb][0];
  49. F(j,1,scr)
  50. s[nb][j]=s[nb][j-1]+f[nb][j];
  51. }
  52. int nb=(n&1);
  53. F(i,1,sum-1)
  54. ans+=f[nb][i];
  55. ans*=(m-1);
  56. printf("%0.15Lf\n",ans+1);
  57. return 0;
  58. }
  59. int rd(void) {
  60. int x=0,f=1; char c=getchar();
  61. while (!isdigit(c)) {
  62. if (c=='-') f=-1;
  63. c=getchar();
  64. }
  65. while (isdigit(c)) {
  66. x=x*10+c-'0';
  67. c=getchar();
  68. }
  69. return x*f;
  70. }

【xsy1800】power - 树链剖分+乘法逆元

分析1

自己YY出来的方法。

单点修改。
子树查询。

代码1

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cctype>
  4. #include <algorithm>
  5. using namespace std;
  6. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  7. #define LD long double
  8. int rd(void);
  9. const int N=128;
  10. const int A=100005;
  11. int n,m;
  12. int rk[N];
  13. int sum;
  14. int scr;
  15. LD f[2][A];
  16. LD s[2][A];
  17. LD ans;
  18. int main(void) {
  19. #ifndef ONLINE_JUDGE
  20. freopen("A.in","r",stdin);
  21. freopen("A.out","w",stdout);
  22. #endif
  23. n=rd(),m=rd();
  24. F(i,1,n)
  25. rk[i]=rd();
  26. F(i,1,n)
  27. sum+=rk[i];
  28. scr=n*m;
  29. f[0][0]=1;
  30. F(j,0,scr)
  31. s[0][j]=1;
  32. F(i,1,n) {
  33. int nb=(i&1);
  34. int rb=(nb^1);
  35. memset(f[nb],0,sizeof f[nb]);
  36. memset(s[nb],0,sizeof s[nb]);
  37. F(j,i*1,i*m) {
  38. int l=j-m;
  39. l=max(l,0);
  40. int r=j-1;
  41. if (l>r)
  42. continue;
  43. f[nb][j]=s[rb][r]-(l==0?0:s[rb][l-1]);
  44. if (l<=j-rk[i]&&j-rk[i]<=r)
  45. f[nb][j]-=f[rb][j-rk[i]];
  46. f[nb][j]/=(m-1);
  47. }
  48. s[nb][0]=f[nb][0];
  49. F(j,1,scr)
  50. s[nb][j]=s[nb][j-1]+f[nb][j];
  51. }
  52. int nb=(n&1);
  53. F(i,1,sum-1)
  54. ans+=f[nb][i];
  55. ans*=(m-1);
  56. printf("%0.15Lf\n",ans+1);
  57. return 0;
  58. }
  59. int rd(void) {
  60. int x=0,f=1; char c=getchar();
  61. while (!isdigit(c)) {
  62. if (c=='-') f=-1;
  63. c=getchar();
  64. }
  65. while (isdigit(c)) {
  66. x=x*10+c-'0';
  67. c=getchar();
  68. }
  69. return x*f;
  70. }

分析2

路径修改。
单点查询。

更简单。
简单得多。。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注