题目链接
https://agc019.contest.atcoder.jp/tasks/agc019_f
题意简述
有n+m个问题,答案都是"Yes"或"No",其中n个是"Yes",m个是"No"。你回答一个问题后,不管是否正确,都可以得到这个问题的答案。假设你都不知道答案只能猜,按最有策略行动,求你期望答对问题的个数。
题解
容易得到一个O(n2)的dp
fi,j=i+jifi−1,j+i+jjfi,j−1+i+jmax(i,j)
设gi,j=fi,j−max(i,j),假设i>j
gi,j+igi,j+igi,j=i+jifi−1,j+i+jjfi,j−1+i+ji=i+ji(gi−1,j+i−1)+i+jj(gi,j−1+i)+i+ji=i+jigi−1,j+i+jjgi,j−1
同理,i<j时上式也成立。
假设i=j
gi,i+igi,i+igi,j=21fi−1,i+21fi,i−1+21=21(gi−1,i+i)+21(gi,i−1+i)+21=21gi−1,i+21gi,i−1+21
综上
gi,j=i+jigi−1,j+i+jjgi,j−1+21[i=j]
上式可以看作从(n,m)出发,在(i,j)每次有i+ji向左走,有i+jj向下走,最终到达(0,0),求经过横坐标等于纵坐标的点的个数的期望的21。这个可以对所有这样的点分开求
i=0∑min(n,m)(nn+m)(n−in+m−2i)(i2i)
那么答案为
max(i,j)+i=0∑min(n,m)(nn+m)(n−in+m−2i)(i2i)
代码
#include <cstdio>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=500000;
const int mod=998244353;
const int inv=499122177;
int n,m,ans,fac[maxn*2+10],ifac[maxn*2+10];
int main()
{
n=read();
m=read();
fac[0]=ifac[0]=ifac[1]=1;
for(int i=1; i<=std::max(n,m)*2; ++i)
{
fac[i]=1ll*fac[i-1]*i%mod;
}
for(int i=2; i<=std::max(n,m)*2; ++i)
{
ifac[i]=1ll*(mod-mod/i)*ifac[mod%i]%mod;
}
for(int i=1; i<=std::max(n,m)*2; ++i)
{
ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
}
ans=std::max(n,m);
for(int i=1; i<=std::min(n,m); ++i)
{
ans=(ans+1ll*fac[n+m-2*i]*fac[2*i]%mod*fac[n]%mod*fac[m]%mod*ifac[n+m]%mod*ifac[n-i]%mod*ifac[m-i]%mod*ifac[i]%mod*ifac[i]%mod*inv)%mod;
}
printf("%d\n",ans);
return 0;
}