[关闭]
@rebirth1120 2019-10-08T18:53:40.000000Z 字数 1344 阅读 797

奥里与属性克制(长郡csp模拟赛)

解题报告


题面大意

有一个元素为 0,1 的序列, 其中 1 的数量为 n, 0 的数量为 m.

一个人会对这个序列的每一位元素进行猜测, 在猜测后, 他会知道自己猜的对不对(也就是知道这个元素是什么).

在猜测的过程中, 他会根据已有的信息来进行最优决策.

求这个人猜对的元素个数的数学期望.

解题思路

以下思路均来自题解

首先, 这个"最优决策"指的是: 每次都猜测剩下更多的那个数.

然后, 这个不确定的序列可以用一个 nm 的网格图来表示

往上走一格, 当前位为 0,
往右走一个, 当前位为 1.
这样, 每一个序列都可以用唯一一条路径来表示.

设图上的点为 ,
时, 这个人猜测的下一个数都是固定的, 所以可以把每个序列的贡献标记为下图

其中, 每经过一条蓝色的边就会得到 1 的贡献,

容易发现, 每个不同的序列都会经过 条蓝边
也就是说, 这个人至少能猜中 个数

所以, 如果忽略 的点, 序列的总贡献就为 ,

时, 这个人就会随便选一个点, 那么不管当前位是 0 还是 1, 都会有 0.5 的贡献.
所以, 我们只要算出点 被经过了多少次, 乘上 0.5, 再加上前面的贡献, 就可以算出所有序列的总贡献,
那么再除上序列总数, 就可以算出期望了, 式子如下( 为点 被经过的次数)

代码实现

  1. #include<iostream>
  2. #include<cstdio>
  3. #define ll long long
  4. using namespace std;
  5. const int N=1000000+7;
  6. const ll mod=998244353;
  7. int ty,n,m;
  8. ll fac[N],invf[N],ans,d;
  9. ll q_pow(ll a,ll p){
  10. ll res=1;
  11. while(p){
  12. if(p&1) res=(res*a)%mod;
  13. p>>=1;
  14. a=(a*a)%mod;
  15. }
  16. return res;
  17. }
  18. ll inv(ll y){ return q_pow(y,mod-2)%mod; }
  19. ll C(int n,int r){
  20. if(n==0||r==0) return 1;
  21. else return fac[n]*invf[r]%mod*invf[n-r]%mod;
  22. }
  23. void pre(){
  24. fac[0]=1;
  25. for(int i=1;i<=n+m;i++) fac[i]=(i*fac[i-1])%mod;
  26. invf[n+m]=inv(fac[n+m]);
  27. for(int i=n+m-1;i>=0;i--) invf[i]=invf[i+1]*(i+1)%mod;
  28. for(int i=1;i<=m;i++) d=(d+C(i+i,i)*C(n-i+m-i,m-i)%mod)%mod;
  29. }
  30. void get(){
  31. ll c=C(m+n,m);
  32. ans=(c*n%mod+inv(2)*d%mod)%mod;
  33. ans=ans*inv(c)%mod;
  34. }
  35. int main(){
  36. //freopen("type.in","r",stdin);
  37. cin>>ty>>n>>m;
  38. if(n<m) swap(n,m);
  39. pre();
  40. get();
  41. printf("%lld\n",ans);
  42. return 0;
  43. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注