AT1983 [AGC001E] BBQ Hard
阿新 • • 發佈:2020-11-21
有 n 個數對 (\(A_i\); \(B_i\)),求出
\[\sum_{i=1}^{n}\sum_{j=i + 1}^{n}{a_i+b_i+a_j+b_j \choose a_i+a_j} \]答案對1e9+7取模
- \(2\le N\le200,000\)
- \(1\le A_i\le2000,\ 1\le B_i\le2000\)
考慮\({a_i+b_i+a_j+b_j \choose a_i+a_j}\)的組合意義,相當於從\((0,0)\)開始,每次只能向右或上走一格走到\((a_i+a_j,b_i+b_j)\)的方案數。
於是我們考慮繼續把這個限制變成從\((-a_i,-b_i)\)走到\((a_j,b_j)\)
那麼我們統計\(\sum_{i=1}^nf_{i,j}\),然後會發現多算了從\((-a_i,-b_i)\)走到\((a_i,b_i)\)的方案,減去\(\sum_{i=1}^n{2(a_i+b_i)\choose 2a_i}\)就可以了。
Code
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> const int N = 2e5; const int M = 2e3; const int p = 1e9 + 7; using namespace std; int n,a[N + 5],b[N + 5],f[M * 2 + 1][M * 2 + 1],fac[N + 5],inv[N + 5],ans; int C(int n,int m) { return 1ll * fac[n] * inv[m] % p * inv[n - m] % p; } int main() { scanf("%d",&n); for (int i = 1;i <= n;i++) scanf("%d%d",&a[i],&b[i]); fac[0] = 1; for (int i = 1;i <= N;i++) fac[i] = 1ll * fac[i - 1] * i % p; inv[1] = 1; for (int i = 2;i <= N;i++) inv[i] = 1ll * (p - p / i) * inv[p % i] % p; inv[0] = 1; for (int i = 1;i <= N;i++) inv[i] = 1ll * inv[i - 1] * inv[i] % p; for (int i = 1;i <= n;i++) f[-a[i] + M][-b[i] + M]++; for (int i = 1;i <= M * 2;i++) f[0][i] += f[0][i - 1],f[0][i] %= p; for (int i = 1;i <= M * 2;i++) { f[i][0] += f[i - 1][0]; f[i][0] %= p; for (int j = 1;j <= M * 2;j++) f[i][j] += (f[i - 1][j] + f[i][j - 1]) % p,f[i][j] %= p; } for (int i = 1;i <= n;i++) ans += (f[a[i] + M][b[i] + M] - C((a[i] + b[i]) * 2,a[i] * 2)) % p,ans %= p; ans = 1ll * ans * inv[2] % p; cout<<(ans + p) % p<<endl; return 0; }