CSP模拟-30D

Neck Deep / 2023-08-25 / 原文

[AGC019F] Yes or No

我们可以试着把所有"最优策略的答题历程"放在一张网状图里。

就像这样。(声明:我们默认\(n \geq m\))

我们认为\((x,y)\)表示还剩\(x\)道答案为\(Yes\)的题,\(y\)同理.

认为向左走为回答\(Yes\),向下为\(No\).

然后你就会发现你啥也发现不了,

答题的过程就是从右上角\((n,m)\)走到\((0,0)\)的过程.

首选易知,我们应该尽可能的让我们的回答尽可能的向\(x=y\)这条直线靠拢.

这个是显然的,因为我们要尽可能的让"无论答案是什么,我们的回答都是正确的"这一事件发生.

我们画出的红线,就是我们的最优策略.

而答案是不确定的,所以其实是"随便走"的"答案"和我们的最优策略的交点,就是我们对的题的数目.


我们可以先随便画出一种答案.

显然,我们可以把\(x=y\)这条直线以上的部分翻折下来——这对结果没有影响.

先抛开竖直的不看,

我们所有的横线都在最优策略所在的红线上,

所以这些横线的总贡献即为\(n\).

但这样只计算了\(x \neq y\)的情况.

再来计算\(x=y\)的情况.

显然我们需要求出经过\(x=y\)这条直线上某一点的概率.

先求出经过某一点的方案数:

\[\binom{n-i+m-i}{n-i} * \binom{i+i}{i} \]

再除以$$\binom{n+m}{n}$$

因为此时向左走和向下走的概率是一样的,所以他们的贡献均为$ \frac{1}{2} $

总起来,可得

\[ans= \sum_{i=1}^{min(n,m)} \binom{n+m-2i}{n-i} \binom{2i}{i} * \frac{1}{2 \binom{n+m}{n} }* max(n,m) \]

点击查看代码


#include<bits/stdc++.h>
using namespace std;
#define il inline
#define endl '\n'
const int N=5e6;
const int mod=998244353;
#define int unsigned long long
#define Croll(i,l,r) for(int i=l;i<=r;++i)
#define Troll(i,l,r) for(int i=l;i>=r;--i)
//////////
namespace solve
{
    int n,m,ans;
    int f[N<<1],g[N<<1];

    int C(int,int);
    int qp(int,int);
    void Wonder_of_U();
}using namespace solve;
//////////
namespace rw
{
    il int read();
    il void write(int);
    il void Write(int);
}using namespace rw;
//////////
main()
{
    n=read();m=read();
    if(n<m)swap(n,m);
    Wonder_of_U();

    Croll(i,1,m)
        ans=(ans+C(2*i,i)*C(n+m-2*i,n-i)%mod*g[2]%mod)%mod;
    ans=(ans*qp(C(n+m,n),mod-2)%mod);
    ans=(ans+n)%mod;
    cout<<ans<<endl;
}
//////////
namespace solve
{
    int C(int n,int m)
    {
        return f[n]*g[m]%mod*g[n-m]%mod;
    }
    int qp(int x,int k)
    {
        int ans=1;
        while(k)
        {
            if(k & 1)ans=ans*x%mod;
            x=x*x%mod;k>>=1;
        }
        return ans;
    }
    void Wonder_of_U()
    {
        f[0]=1;g[0]=1;
        Croll(i,1,n<<1)
            f[i]=f[i-1]*i%mod,
            g[i]=g[i-1]*qp(i,mod-2)%mod;
    }
}
//////////
namespace rw
{
    il void write(int x)
    {Write(x);cout<<endl;}
    il int read()
    {
        int f=1,x=0;char w=getchar();
        while(w<'0'||w>'9')
        {if(w=='-')f=-1;w=getchar();}
        while(w>='0'&&w<='9')
        {x=(x<<3)+(x<<1)+(w^48);w=getchar();}
        return f*x;
    }
    il void Write(int x)
    {
        if(x<0) putchar('-'),x=-x;
        if(x>9) Write(x/10);
        putchar(x%10+'0');
    }
}