其他分享
首页 > 其他分享> > 题解 【AT1983 [AGC001E] BBQ Hard】

题解 【AT1983 [AGC001E] BBQ Hard】

作者:互联网

\(\large\mathcal{Description}\)

有 \(n\) 个数对 \((A_i,A_j)\). 求:

\[\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n{a_i+b_i+a_j+b_j \choose a_i+a_j} \]

答案对 \(10^9+7\) 取模.

\(\large\mathcal{Solution}\)

暴力求解上述式子是 \(\mathcal{O}(n^2)\) 的,我们考虑如何优化它。

给出引理:在平面直角坐标系中,点 \((x_1, y_1)\) 为起点, \((x_2,y_2)\) 为终点,每次只能往右或往上走(\(x_2\ge x_1, y_2\ge y_1\))。则方案数为:

\[y_2-x_2+y_1-x_1 \choose y_2-x_2 \]

感性理解:从 \((x_1, y_1)\) 到 \((x_2,y_2)\) 要走 \(y_2-x_2+y_1-x_1\) 步,其中 \(y_2-x_2\) 步向上走。

由上述引理,得知组合数的几何意义: \(a_i+b_i+a_j+b_j \choose a_i+a_j\) 为从 \((-a_i, -b_i)\) 到 \((a_j, b_j)\) 的方案数。发现:起点只与 \(i\) 有关, 终点只与 \(j\) 有关。

令 \(f(i,\ j)\) 表示 \((i, j)\) 到所有 \((-a_x, -b_x)_{1\le x\le n}\) 路径条数之和。

\(f(i,\ j)\) 是容易用 \(\text{dp}\) 处理的,方法如下:

答案自然就是 \(\sum\limits_{i=1}^nf(a_i,\ b_i)\) 再减去每个 \((a_i,b_i)\) 到 \((-a_i,-b_i)\) 路径条数之和。

即:

\[\sum\limits_{i=1}^nf(a_i,\ b_i)-\sum\limits_{i=1}^n {2a_i+2b_i \choose 2a_i} \]

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

\(\large\mathcal{Code}\)

#include <bits/stdc++.h>
#define reg register

using namespace std;

const int N = 200010, S = 2010;
const int mod = 1000000007;

int n, a[N], b[N];
int frac[N], inv[N], ifrac[N];
int f[2 * S + 10][2 * S + 10];

void pre()
{
	frac[0] = inv[1] = ifrac[0] = 1;
	for (reg int i = 1; i <= 4 * S; ++ i) frac[i] = 1ll * i * frac[i - 1] % mod;
	for (reg int i = 2; i <= 4 * S; ++ i) inv[i] = (mod - 1ll * (mod / i) * inv[mod % i] % mod) % mod;
	for (reg int i = 1; i <= 4 * S; ++ i) ifrac[i] = 1ll * inv[i] * ifrac[i - 1] % mod;
}

int C(int n, int m)
{
	return 1ll * frac[n] * ifrac[m] % mod * ifrac[n - m] % mod;
}

int main()
{
	scanf("%d", &n);
	for (reg int i = 1; i <= n; ++ i) scanf("%d %d", &a[i], &b[i]);
	
	pre();
	
	for (reg int i = 1; i <= n; ++ i) f[S - a[i]][S - b[i]] ++ ;
	for (reg int i = 1 - S; i <= S; ++ i)
	    for (reg int j = 1 - S; j <= S; ++ j)
	        f[i + S][j + S] = ((f[i + S][j + S] + f[i + S - 1][j + S]) % mod + f[i + S][j + S - 1]) % mod;
	
	int ans = 0;
	for (reg int i = 1; i <= n; ++ i)
	{
		ans = (ans + f[S + a[i]][S + b[i]]) % mod;
		ans = (ans - C(2 * a[i] + 2 * b[i], 2 * a[i]) + mod) % mod;
	}
	printf("%d\n", 1ll * ans * inv[2] % mod);
	
	return 0;
}

标签:large,limits,int,题解,sum,Hard,AT1983,choose,mathcal
来源: https://www.cnblogs.com/DreamsChaser/p/15010780.html