@rebirth1120
2019-10-08T10:53:40.000000Z
字数 1344
阅读 1001
解题报告
有一个元素为 0,1 的序列, 其中 1 的数量为 n, 0 的数量为 m.
一个人会对这个序列的每一位元素进行猜测, 在猜测后, 他会知道自己猜的对不对(也就是知道这个元素是什么).
在猜测的过程中, 他会根据已有的信息来进行最优决策.
求这个人猜对的元素个数的数学期望.
以下思路均来自题解
首先, 这个"最优决策"指的是: 每次都猜测剩下更多的那个数.
然后, 这个不确定的序列可以用一个 nm 的网格图来表示
往上走一格, 当前位为 0,
往右走一个, 当前位为 1.
这样, 每一个序列都可以用唯一一条路径来表示.
设图上的点为 ,
当 时, 这个人猜测的下一个数都是固定的, 所以可以把每个序列的贡献标记为下图
其中, 每经过一条蓝色的边就会得到 1 的贡献,
容易发现, 每个不同的序列都会经过 条蓝边
也就是说, 这个人至少能猜中 个数
所以, 如果忽略 的点, 序列的总贡献就为 ,
当 时, 这个人就会随便选一个点, 那么不管当前位是 0 还是 1, 都会有 0.5 的贡献.
所以, 我们只要算出点 被经过了多少次, 乘上 0.5, 再加上前面的贡献, 就可以算出所有序列的总贡献,
那么再除上序列总数, 就可以算出期望了, 式子如下( 为点 被经过的次数)
#include<iostream>#include<cstdio>#define ll long longusing namespace std;const int N=1000000+7;const ll mod=998244353;int ty,n,m;ll fac[N],invf[N],ans,d;ll q_pow(ll a,ll p){ll res=1;while(p){if(p&1) res=(res*a)%mod;p>>=1;a=(a*a)%mod;}return res;}ll inv(ll y){ return q_pow(y,mod-2)%mod; }ll C(int n,int r){if(n==0||r==0) return 1;else return fac[n]*invf[r]%mod*invf[n-r]%mod;}void pre(){fac[0]=1;for(int i=1;i<=n+m;i++) fac[i]=(i*fac[i-1])%mod;invf[n+m]=inv(fac[n+m]);for(int i=n+m-1;i>=0;i--) invf[i]=invf[i+1]*(i+1)%mod;for(int i=1;i<=m;i++) d=(d+C(i+i,i)*C(n-i+m-i,m-i)%mod)%mod;}void get(){ll c=C(m+n,m);ans=(c*n%mod+inv(2)*d%mod)%mod;ans=ans*inv(c)%mod;}int main(){//freopen("type.in","r",stdin);cin>>ty>>n>>m;if(n<m) swap(n,m);pre();get();printf("%lld\n",ans);return 0;}
