AT1983 [AGC001E] BBQ Hard(組合計數)
阿新 • • 發佈:2021-11-11
題意
有 \(n\) 個數對 \((a_i,b_i)\),求:
\(\sum_{i=1}^{n} \sum_{j=i+1}^{n} C_{a_i+b_i+a_j+b_j}^{a_i+a_j}\)
資料範圍
\(2 \leq N \leq 200000\)。
\(1\leq a_i,b_i \leq 2000\)。
思路
預處理出階層,直接列舉的時間複雜度為 \(O(n^2)\)。顯然需要更優的做法。
可以考慮題目要求的式子的幾何意義,\(C_{a_i+b_i+a_j+b_j}^{a_i+a_j}\) 可以看成是從直角座標系的原點 \((0,0)\),只向上或向右走,走到 \((a_i+a_j,b_i+b_j)\)
但是這樣還是無法做到更優的複雜度。可以考慮進一步轉化為從 \((-a_i,-b_i)\) 走到 \((a_j,b_j)\) 的方案數,含義不變。對於每一個終點 \((a_i,b_i)\),都可以從所有的 \((-a_j,-b_j)\) 走過來,可以直接 \(O(\max (a_i+a_j)^2)\) dp 算出所有的答案(具體實現可以看程式碼)。這樣計算會多算 \(i \geq j\) 的方案,於是可以先減去從 \((-a_i,-b_i)\)
最終的時間複雜度就是 \(O(n+4000^2)\)。
code:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int mod=1e9+7; const int N=4040,NLC=2020,M=2e5+10; int f[N][N],ans,n,inv[N<<1],fac[N<<1],infac[N<<1],a[M],b[M]; void init() { fac[0]=fac[1]=inv[0]=inv[1]=infac[0]=infac[1]=1; for(int i=2;i<N<<1;i++) { fac[i]=1ll*fac[i-1]*i%mod; inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; infac[i]=1ll*infac[i-1]*inv[i]%mod; } } int C(int n,int m){return 1ll*fac[n]*infac[m]%mod*infac[n-m]%mod;} int main() { init(); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]),f[NLC-a[i]][NLC-b[i]]++;//直接儲存負數會 RE,需要整體加上一個偏移量 for(int i=1;i<N;i++) for(int j=1;j<N;j++) f[i][j]=(f[i][j]+f[i][j-1]+f[i-1][j])%mod; for(int i=1;i<=n;i++) { ans=(ans+f[NLC+a[i]][NLC+b[i]])%mod; ans=((ans-C(2*a[i]+2*b[i],2*a[i]))%mod+mod)%mod; } printf("%d\n",1ll*ans*inv[2]%mod); return 0; }