把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

[AGC001E] BBQ Hard 分析

题目概述

给出 \(n\)\(a_i,b_i\),其中 \(a_i\) 代表 \(0\) 的个数,\(b_i\) 代表 \(1\) 的个数,让你求对于所有的 \((i,j)(i<j)\) 这些 \(0,1\) 组合起来的本质不同的个数之和。

分析

思维好题!

首先我们不难想到卡特兰数的方法去求他后面这些东西。换言之,题目转化为求:

\[\sum_{i=1}^n\sum_{j=i+1}^n\binom{a_i+b_i+a_j+b_j}{a_i+a_j} \]

显然这个可以变成:

\[\frac 1 2\left(\sum_{i=1}^n\sum_{j=1}^n\binom{a_i+b_i+a_j+b_j}{a_i+a_j}-\sum_{i=1}^n\binom{2a_i+2b_i}{2a_i}\right) \]

考虑怎么求前面的那一个。

我们注意到我们的本质是从 \((0,0)\rightarrow (a_i+a_j,b_i+b_j)\)

一个巧妙的转化:将他变成 \((-a_i,-b_i)\rightarrow(a_j,b_j)\)

然后就很简单了,这是一个组合数递推问题,将一开始赋为 \(1\) 即可。

然后这题目就做完了。

代码

时间复杂度 \(\mathcal{O}(n+\max a_i^2)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#define int long long
#define N 200005
using namespace std;
const int mod = 1e9 + 7;
int jc[N],inv[N];
int C(int a,int b) {
    if (a < 0 || b < 0 || a < b) return 0;
    return jc[a] * inv[b] % mod * inv[a - b] % mod;
}
void pls(int &x,int y) {
    (x += y) %= mod;
}
int n,a[N],b[N],f[4005][4005];
signed main(){
    jc[0] = inv[0] = jc[1] = inv[1] = 1;
    for (int i = 2;i < N;i ++) jc[i] = jc[i - 1] * i % mod,inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    for (int i = 2;i < N;i ++) inv[i] = inv[i - 1] * inv[i] % mod;
    cin >> n;
    int delt = 2000,ans = 0;
    for (int i = 1;i <= n;i ++) scanf("%lld%lld",&a[i],&b[i]),f[-a[i] + delt][-b[i] + delt] ++,ans += C(2 * a[i] + 2 * b[i],2 * a[i]),ans %= mod;
    for (int i = 0;i <= 4000;i ++)
        for (int j = 0 + (i == 0);j <= 4000;j ++) {
            if (i) pls(f[i][j],f[i - 1][j]);
            if (j) pls(f[i][j],f[i][j - 1]);
        }
    ans = (-ans + mod) % mod;
    for (int i = 1;i <= n;i ++) ans = (ans + f[a[i] + delt][b[i] + delt]) % mod;
    cout << ans * (mod + 1) / 2 % mod;
    return 0;
}

后记

最近打 ABC 有类似题:abc432_g

但是值域很大,不能用这种方法做,只能考虑 poly trick。

posted @ 2025-11-16 22:06  high_skyy  阅读(3)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end