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[i1][j]+f[i][j1]

最后减掉 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;
}
posted @ 2021-10-31 17:41  lahlah  阅读(23)  评论(0编辑  收藏  举报