【AGC019F】Yes or No
阿新 • • 發佈:2021-08-06
題目
題目連結:https://atcoder.jp/contests/agc019/tasks/agc019_f
有 \(N+M\) 個問題,其中有 \(N\) 個問題的答案是 YES
,\(M\) 個問題的答案是 NO
。當你回答一個問題之後,會知道這個問題的答案,求最優策略下期望對多少。
答案對 \(998244353\) 取模。
思路
假設目前已經確定剩餘 \(n\) 個 YES
,\(m\) 個 NO
,那麼最優策略肯定是猜更多的那一邊。
把選擇 YES
看作是向左走一個單位長度,選擇 NO
看作是向下走一個單位長度,那麼這 \(n+m\) 個選擇可以看作是從 \((n,m)\) 走向 \((0,0)\) 的一條路徑。
對於一個點 \((x,y)\)
設 \(n\geq m\),可以把直線 \(f(x)=x\) 左上方的網格直接翻折過來,發現每一條從 \((n,m)\) 到 \((0,0)\) 的路徑,經過的標記邊的數量就是 \(n+\) 走到直線 \(f(x)=x\) 且下一步往左的次數。
那麼只需要對於直線 \(f(x)=x\) 的每一個點都求出有多少條路徑會經過這一個點即可。組合數隨便搞搞不難發現答案就是
時間複雜度 \(O(n+m)\)。
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1000010,MOD=998244353,inv2=499122177; int n,m; ll ans,fac[N],inv[N]; ll fpow(ll x,ll k) { ll ans=1; for (;k;k>>=1,x=x*x%MOD) if (k&1) ans=ans*x%MOD; return ans; } ll C(int n,int m) { return fac[n]*inv[m]%MOD*inv[n-m]%MOD; } int main() { scanf("%d%d",&n,&m); fac[0]=inv[0]=1; for (int i=1;i<=n+m;i++) fac[i]=fac[i-1]*i%MOD; inv[n+m]=fpow(fac[n+m],MOD-2); for (int i=n+m-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%MOD; 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; cout<<(ans*inv2%MOD*fpow(C(n+m,n),MOD-2)+n)%MOD; return 0; }