ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 【AT1983 [AGC001E] BBQ Hard】

2021-07-14 15:01:07  阅读:173  来源: 互联网

标签:large limits int 题解 sum Hard AT1983 choose mathcal


\(\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}\) 处理的,方法如下:

  • 对于 \(\forall x\in\{1,2,\cdots,n\}\),令 \(f_{a_i,\ b_i} \leftarrow 1\)
  • 对所有格子执行 \(f_{i, j} = f_{i, j - 1} + f_{i - 1, j}\).

答案自然就是 \(\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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有