[AGC001E] BBQ Hard

AT 的题质量就是高。

首先我们发现题目要我们求 (displaystylesum_{i=1}^{n}sum_{j=i+1}^{n} inom{a_i+a_j+b_i+b_j}{a_i+a_j})

然后直接预处理组合数过不了。

那么我们想想这个东西的组合意义是什么。

对,就是求从 ((0,0))((a_i + a_j, b_i + b_j)) 的路径数量。

那么我们平移一下,就转化成求 ((-a_i,-b_i))((a_j,b_j)) 的路径数量。

考虑 dp,初始先让所有 (dp_{-a_i,-b_i})(1),转移方程就是 (dp_{i,j}=dp_{i,j}+dp_{i-1,j}+dp_{i,j-1})

题目要求 (i eq j)(i<j) 所以我们的答案就是所有的 (dp_{a_i,b_i}) 加起来,然后减去从 ((-a_i,-b_i))((a_i, b_i)) 的路径数量,然后除以 (2)

#include <bits/stdc++.h>
#define reg register
#define ll long long
using namespace std;
const int MAXN = 2e5 + 10;
const int MAXM = 8010;
const int mod = 1e9 + 7;
int n, a[MAXN], b[MAXN], fac[MAXM], inv[MAXM], dp[MAXM / 2 + 10][MAXM / 2 + 10], total = MAXM / 4 + 2;
int fastpow(int a, int b) {
  int ret = 1;
  while(b) {
    if(b & 1) ret = 1ll * ret * a % mod;
    b >>= 1, a = 1ll * a * a % mod;
  }
  return ret;
}
int getc(int n, int m) {
  return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;
}
inline void work() {
  fac[1] = inv[1] = 1;
  for(reg int i = 2; i <= MAXM - 10; ++i) fac[i] = 1ll * fac[i - 1] * i % mod, inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
  for(reg int i = 2; i <= MAXM - 10; ++i) inv[i] = 1ll * inv[i] * inv[i - 1] % mod;
  scanf("%d", &n);
  for(reg int i = 1; i <= n; ++i) scanf("%d%d", &a[i], &b[i]), ++dp[total - a[i]][total - b[i]];
  for(reg int i = 1; i <= MAXM / 2; ++i) for(reg int j = 1; j <= MAXM / 2; ++j) dp[i][j] = (dp[i][j] + (dp[i][j - 1] + dp[i - 1][j]) % mod) % mod;
  int ans = 0;
  for(reg int i = 1; i <= n; ++i) ans = (ans + dp[a[i] + total][b[i] + total]) % mod, ans = (ans - getc(a[i] * 2 + b[i] * 2, a[i] * 2) + mod) % mod;
  printf("%d
", 1ll * ans * fastpow(2, mod - 2) % mod);
}
int main() {
  int _ = 1;
  // scanf("%d", &_);
  while(_--) work();
  return 0;
}
原文地址:https://www.cnblogs.com/Lonely-233/p/13659117.html