[AGC019F] Yes or No
阿新 • • 發佈:2021-06-26
tag:組合計數
題意
有 \(n\) 個回答yes的問題和 \(m\) 個回答no的問題,求最優策略下期望回答正確的答案個數,回答一個問題後立刻可以知道是否回答正確。
\(n,m\leq5\cdot10^5,\ mod=998244353\)
首先我很naive地認為最優策略是亂回答
最優策略是:假設當前還剩了 \(a\) 個yes問題和 \(b\) 個no問題
- \(a<b\) 回答yes
- \(a\ge b\) 回答no
顯然這樣回答正確的概率是最高的
可以抽象出一個問題,從 \((n,m)\) 走到 \((0,0)\),每一步只能往左/下。於是根據最優策略,我們可以確定在每個點,下一步會走向的位置。
(從粉兔那兒賀了一張圖)
然後每一種問題組合就剛好對應著一條從 \((n,m)\) 到 \((0,0)\) 的路徑,所以問題變為每一條路徑經過的紅色線段數量和,除以路徑條數。
對於這種網格圖路徑和經過斜線問題,一般想到翻折。對於一條經過斜線的路經,把在斜線上方的部分翻折下來,發現經過的線段數會減少(路徑與斜線的交點個數-1);巧妙的是,對於任意路徑,這樣翻折以後會經過的線段數都是 \(n\)。
所以 \(ans=n+E(\)交點個數\()-E(\)經過斜線的路徑數\()\),可以列舉每一個交點計算貢獻。
\[ans=n+\dfrac{\sum_{i=0}^{\min\{n,m\}}\binom{2i}{i}\binom{n-i+m-i}{n-i}-\binom{n+m}{n}}{\binom{n+m}n} \]#include<bits/stdc++.h> using namespace std; template<typename T> inline void Read(T &n){ char ch; bool flag=0; while(!isdigit(ch=getchar()))if(ch=='-')flag=1; for(n=ch^48;isdigit(ch=getchar());n=((n<<1)+(n<<3)+(ch^48))%998244353); if(flag)n=-n; } enum{ MAXN = 500005, MOD = 998244353, inv2 = MOD+1>>1 }; int n, m; int jc[MAXN<<1], invjc[MAXN<<1]; inline int ksm(int base, int k=MOD-2){ int res=1; while(k){ if(k&1) res = 1ll*res*base%MOD; base = 1ll*base*base%MOD; k >>= 1; } return res; } inline void prework(int n){ jc[0] = 1; for(register int i=1; i<=n; i++) jc[i] = 1ll*jc[i-1]*i%MOD; invjc[n] = ksm(jc[n]); for(register int i=n; i; i--) invjc[i-1] = 1ll*invjc[i]*i%MOD; } inline int C(int n, int m){return 1ll*jc[n]*invjc[m]%MOD*invjc[n-m]%MOD;} inline int dec(int a, int b){ a -= b; if(a<0) a += MOD; return a; } int ans=0; int main(){ Read(n); Read(m); prework(n+m); for(register int i=0; i<=n and i<=m; i++) ans = (ans+1ll*C(i+i,i)*C(n-i+m-i,n-i))%MOD; ans = dec(ans,C(n+m,n)); printf("%lld\n",(max(n,m)+1ll*inv2*ans%MOD*ksm(C(n+m,n)))%MOD); return 0; }