AT1983 [AGC001E] BBQ Hard
https://www.luogu.com.cn/problem/AT1983
由基本的组合数知识,我们知道
( a i + b i + a j + b j a i + a j ) \binom{a_i+b_i+a_j+b_j}{a_i+a_j} (ai+ajai+bi+aj+bj)相当于是从 ( 0 , 0 ) (0,0) (0,0)走到 ( a i + a j , b i + b j ) (a_i+a_j,b_i+b_j) (ai+aj,bi+bj)的方案数
然而
i
,
j
i,j
i,j还是没有分开,依然不好做
我们考虑坐标偏移一下
上面的那个组合数也可以相当于是
从 ( − a i , − b i ) (-a_i,-b_i) (−ai,−bi)走到 ( a j , b j ) (a_j,b_j) (aj,bj)的方案数,这样一下子就感觉可做的许多
先把 f [ − a i ] [ − b i ] + + f[-a_i][-b_i]++ f[−ai][−bi]++然后正常的转移 f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i ] [ j − 1 ] f[i][j]=f[i-1][j]+f[i][j-1] f[i][j]=f[i−1][j]+f[i][j−1]
最后减掉 i i i到 i i i的贡献再 / 2 /2 /2就可以得到答案了
code:
#include<bits/stdc++.h>
#define N 4005
#define ll long long
#define mod 1000000007
using namespace std;
ll qpow(ll x, ll y) {
ll ret = 1;
for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
return ret;
}
ll fac[N << 1], ifac[N << 1];
void init(int n) {
fac[0] = 1;
for(int i = 1; i <= n; i ++) fac[i] = fac[i - 1] * i % mod;
ifac[n] = qpow(fac[n], mod - 2);
for(int i = n - 1; i >= 0; i --) ifac[i] = ifac[i + 1] * (i + 1) % mod;
}
ll C(int n, int m) {
return fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
const int py = 2001;
ll f[N << 1][N << 1];
int n, a[200050], b[200050];
int main() {
scanf("%d", &n);
init(8000);
for(int i = 1; i <= n; i ++) {
scanf("%d%d", &a[i], &b[i]);
f[- a[i] + py][- b[i] + py] ++;
}
for(int i = 1; i <= 2 * py; i ++)
for(int j = 1; j <= 2 * py; j ++)
f[i][j] += f[i - 1][j] + f[i][j - 1], f[i][j] %= mod;
ll ans = 0;
for(int i = 1; i <= n; i ++) {
ans = (ans + f[a[i] + py][b[i] + py]) % mod;
ans = (ans - C(a[i] * 2 + b[i] * 2, 2 * a[i]) + mod) % mod;
}
printf("%lld", ans * qpow(2, mod - 2) % mod);
return 0;
}