版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/82976700
分析:
首先,很容易搞出来一个N^2的DP做法,显然会T,但是对发现正解有很大帮助:
将这个DP转换为一个网格,就变为:从起始点(n,m)出发,到达目标点(0,0)的期望路径长度。
首先,有一个很厉害的结论:因为每次都是按照最优策略选答案,所以不妨设n>=m,那么一定能答对n次。证明很显然,每次当n>m时我们都会n的那一项,尽管答案可能会错,但错了之后,n会更大,我们更会选n。直到最终没有m了,或者终于答对一次,n减少1。
有了这个结论以及其证明的过程,显然不在对角线(i,i)上的点已经不用考虑了。其选择方案之和永远为n。
显然,在对角线上的点,我们只能随便选一个答案,无论选哪个都将离开对角线,并且期望得分都为1/2。
因此,我们可以爆枚每个对角线上的点被选中的概率,把它乘以1/2累加起来即可。
最后把累加的和加上n就做完了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 1000010
#define MOD 998244353
using namespace std;
typedef long long ll;
ll fac[MAXN],ifac[MAXN];
ll ans;
ll fsp(ll x,int y){
ll res=1;
while(y){
if(y&1)
res=res*x%MOD;
x=x*x%MOD;
y>>=1;
}
return res;
}
void prepare(){
fac[0]=1;
for(int i=1;i<=1000000;i++)
fac[i]=fac[i-1]*i%MOD;
ifac[1000000]=fsp(fac[1000000],MOD-2);
for(int i=1000000;i>=1;i--)
ifac[i-1]=ifac[i]*i%MOD;
}
ll C(int n,int m){
return fac[n]*ifac[m]%MOD*ifac[n-m]%MOD;
}
int main(){
int n,m;
prepare();
SF("%d%d",&n,&m);
if(n<m)
swap(n,m);
for(int i=1;i<=m;i++)
ans=(ans+C(2*i,i)*C(n+m-2*i,n-i)%MOD)%MOD;
ans=ans*fsp(2ll*C(n+m,n)%MOD,MOD-2)%MOD;
ans=(ans+n)%MOD;
PF("%lld",ans);
}