LuoGu: AT1983 [AGC001E] BBQ Hard
AtCoder: E - BBQ Hard
考虑计算 $\displaystyle \sum _ {i = 1} ^ n \sum _ {j = 1} ^ n f _ {i, j}$ ,将自己对自己的贡献减去后除以 $2$ 即为答案。
考虑组合意义,$\binom {a _ i + b _ i + a _ j + b _ j} {a _ i + a _ j}$ 表示从 $(0, 0)$ 到 $(a _ i + a _ j, b _ i + b _ j)$ 只向上或右走的方案数,平移,也就是 $(-a _ j, -b _ j)$ 到 $(a _ i, b _ i)$ 的方案数。
这样 $O(m ^ 2)$ DP 算而不是用数学算可以对于每一个元素 $O(1)$ 获得所有元素对他的贡献。
查看代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include <cstdio> using namespace std;template <class Type >void read (Type &x) { char c; bool flag = false ; while ((c = getchar ()) < '0' || c > '9' ) c == '-' && (flag = true ); x = c - '0' ; while ((c = getchar ()) >= '0' && c <= '9' ) x = (x << 3 ) + (x << 1 ) + c - '0' ; if (flag) x = ~x + 1 ; } template <class Type , class ...rest >void read (Type &x, rest &...y) { read (x), read (y...); }template <class Type >void write (Type x) { if (x < 0 ) putchar ('-' ), x = ~x + 1 ; if (x > 9 ) write (x / 10 ); putchar (x % 10 + '0' ); } typedef long long LL;const int N = 2e5 + 10 , M = 2e3 + 10 , mod = 1e9 + 7 ;void adj (int &x) { x += x >> 31 & mod; };int binpow (int b, int k) { int res = 1 ; for (; k; b = (LL)b * b % mod, k >>= 1 ) if (k & 1 ) res = (LL)res * b % mod; return res; } int n, A[N], B[N], f[M << 1 ][M << 1 ];int inv[M << 2 ], fact[M << 2 ], ifact[M << 2 ];void init () { inv[1 ] = 1 ; for (int i = 2 ; i < M << 2 ; i++) inv[i] = (LL)(mod - mod / i) * inv[mod % i] % mod; fact[0 ] = ifact[0 ] = 1 ; for (int i = 1 ; i < M << 2 ; i++) { fact[i] = (LL)fact[i - 1 ] * i % mod; ifact[i] = (LL)ifact[i - 1 ] * inv[i] % mod; } } int C (int a, int b) { return (LL)fact[a] * ifact[a - b] % mod * ifact[b] % mod; }int main () { read (n); for (int i = 1 ; i <= n; ++i) { read (A[i], B[i]); f[M - A[i]][M - B[i]]++; } init (); for (int i = 1 ; i < M << 1 ; ++i) for (int j = 1 ; j < M << 1 ; ++j) adj (f[i][j] += f[i - 1 ][j] - mod), adj (f[i][j] += f[i][j - 1 ] - mod); int res = 0 ; for (int i = 1 ; i <= n; i++) { adj (res += f[M + A[i]][M + B[i]] - mod); adj (res -= C ((A[i] << 1 ) + (B[i] << 1 ), A[i] << 1 )); } adj (res = (LL)res * inv[2 ] % mod); write (res); return 0 ; }