题面
题意
你要做一共 ( n + m ) (n+m) (n+m)道判断题,其中有m道题的答案是对,n道题的答案是错,当你做一道题之后,就可以知道对错,则你期望最多能做对多少题。
做法
首先最优方法肯定是写当前剩余数量最多的答案,我们可以将求正确期望改为求错误期望,对此建一张图:
横纵坐标分别表示此时剩下的答案数,自下而上的边表示此时答案是对的题较多但正确答案是错,自右向左的边则相反,这样将每条边的权值为设1,答案就可以转化为从右下角到左上角的路径的边权和的期望,为了求这个,可以先加一些边,再把新加的边的贡献减掉:
可以发现这张图一共添加了
min
(
m
,
n
)
\min(m,n)
min(m,n)条边,而且这张图中任意一条从左下角到右上角的路径的权值都是
min
(
m
,
n
)
\min(m,n)
min(m,n),很好计算,而新加的边的贡献就是经过这条边的路径数,也很好计算。
代码
#include<bits/stdc++.h>
#define ll long long
#define N 1001000
#define MN 1000000
#define M 998244353
using namespace std;
ll n,m,ans,jc[N],nj[N];
inline ll C(ll u,ll v){return jc[u]*nj[v]%M*nj[u-v]%M;}
inline ll po(ll u,ll v)
{
ll res=1;
for(;v;)
{
if(v&1) res=res*u%M;
u=u*u%M;
v>>=1;
}
return res;
}
int main()
{
ll i,j;
jc[0]=1;for(i=1;i<=MN;i++) jc[i]=jc[i-1]*i%M;
nj[MN]=po(jc[MN],M-2);for(i=MN-1;i>=0;i--) nj[i]=nj[i+1]*(i+1)%M;
cin>>m>>n;
if(m>n) swap(m,n);
ans=C(m+n,m)*m%M;
for(i=1;i<=m;i++)
{
ans-=C(2*i-1,i)*C(m+n-2*i,n-i)%M;
ans%=M;
}
ans=(ans+M)%M;
cout<<(m+n-ans*po(C(m+n,m),M-2)%M+M)%M;
}