[AtCoder Grand Contest 019] F: Yes or No (agc019F)

原题链接
https://agc019.contest.atcoder.jp/tasks/agc019_f

Description

有N+M个问题,N个问题的答案是Yes,M个问题的答案是No

现在将这N+M个问题随机排列
你需要按顺序回答,每回答一个问题就会告诉你这道题的正确答案

求最优策略下答对问题的期望数量
答案对998244353取模
n,m<=5e5

Solution

显然,最优策略一定是哪一个多选哪个

假设当前有x个问题是Yes,y个问题是No

不妨用点(x,y)表示

那么原问题就转换到网格图上

这里写图片描述

如图,N=5,M=4
横坐标看做N,纵坐标看做M

一种题目的排列就对应了从右上角到左下角的一条路径

红线就是y=x的直线
红线下方表示 y<x y < x ,此时我们回答Yes,红线上方表示 y>x y > x ,此时回答No

那么只要经过一次蓝色的边都代表答对一次

可以发现无论路径怎么走,经过的蓝边都是max(n,m)次

此时只剩下当y=x时我们怎么选
当y=x时我们会乱选一个,1/2机会对

那么统计y=x上每个点经过它的路径数,乘上1/2

再除以总路径数,加上max(n,m)就是答案

Code

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define mo 998244353
#define LL long long
#define N 1000005
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
LL js[N],ny[N];
LL ksm(LL k,LL n)
{
    LL s=1;
    for(;n;k=k*k%mo,n>>=1) if(n&1) s=s*k%mo;
    return s;
}
LL C(LL n,LL m)
{
    return js[n]*ny[m]%mo*ny[n-m]%mo;
}
int main()
{
    int n,m;
    cin>>n>>m;
    if(n<m) swap(n,m);
    js[0]=1;
    fo(i,1,n*2) js[i]=js[i-1]*(LL)i%mo;
    ny[2*n]=ksm(js[2*n],mo-2);
    fod(i,2*n-1,0) ny[i]=ny[i+1]*(LL)(i+1)%mo;
    LL ans=0;
    fo(i,1,m) 
    {
        ans=(ans+C(n+m-i-i,n-i)*C(i+i,i)%mo)%mo;
    }
    ans=ans*ny[2]%mo*ksm(C(n+m,m),mo-2)%mo;
    printf("%lld\n",(ans+n)%mo);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值