题面
题解
先化简一下
[displaystyle egin{aligned}&sum_{i = 1}^{n}sum_{j = i + 1}^{n}inom{a_i+a_j+b_i+b_j}{a_i+a_j}\=&frac{sum_{i = 1}^{n}sum_{j = 1}^{n}inom{a_i+a_j+b_i+b_j}{a_i+a_j}-sum_{i = 1}^{n}inom{2*a_i+2*b_i}{2*a_i}}{2}end{aligned}
]
后面那个可以 (O(n)) 地算出来
所以现在的问题就是前面这个东西怎么算
仔细观察一下括号内的东西, 发现可以把他变成网格图计数
就是 ((0, 0)) 到 ((a_i + a_j, b_i + b_j)) 的路径数
再换一下, 变成从 ((-a_i, -b_i)) 到 ((a_j, b_j)) 的方案数
考虑到 (a) 和 (b) 都很小, 你网格图跑一遍路径和就完了
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int mod = 1000000007;
const int N = 4005;
const int M = 8000;
using namespace std;
int f[N + 505][N + 505], a[200005], b[200005], fac[M << 1], inv[M << 1], base, ans, n;
template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}
int fpow(int x, int y)
{
int res = 1;
while(y)
{
if(y & 1)
res = 1ll * res * x % mod;
x = 1ll * x * x % mod;
y >>= 1;
}
return res;
}
int C(int n, int m) { return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod; }
int main()
{
n = read <int> (), base = 2002;
for(int i = (fac[0] = 1); i <= M; i++)
fac[i] = 1ll * fac[i - 1] * i % mod;
inv[M] = fpow(fac[M], mod - 2);
for(int i = M - 1; i >= 0; i--)
inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
for(int i = 1; i <= n; i++)
{
a[i] = read <int> (), b[i] = read <int> ();
f[base - a[i]][base - b[i]]++;
}
for(int i = 1; i <= base + 2000; i++)
for(int j = 1; j <= base + 2000; j++)
f[i][j] = (1ll * f[i][j] + f[i - 1][j] + f[i][j - 1]) % mod;
for(int i = 1; i <= n; i++)
{
ans = (1ll * ans + f[base + a[i]][base + b[i]]) % mod;
ans = (1ll * ans - C(2 * a[i] + 2 * b[i], 2 * a[i])) % mod;
}
ans = (ans + mod) % mod;
ans = 1ll * ans * 500000004 % mod;
printf("%d
", ans);
return 0;
}