【AGC001E】BBQ Hard

题目

题目链接:https://atcoder.jp/contests/agc001/tasks/agc001_e
有 n 个数对 (\(a_i,b_i\)),求

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

答案对 \(10^9+7\) 取模。
\(n\leq 200000;1\leq a_i,b_i\leq 2000\)

思路

观察到 \(a,b\) 的取值范围很小,所以复杂度肯定是有关 \(a,b\) 的。
考虑 \({a_i+b_i+a_j+b_j \choose a_i+a_j}\) 的组合意义,其实就是从 \((0,0)\) 走到 \((a_i+a_j,b_i+b_j)\) 且只能往上和往右的方案数。
这样还是不好搞,我们可以把起点和终点的横纵坐标分别减去 \(a_i\)\(b_i\),也就是从 \((-a_i,-b_i)\) 走到 \((a_j,b_j)\) 的方案数。
这样起点和终点就分别只和 \(i,j\) 有关了。初始化 \(f[x][y]=\) 集合 \(\{i|a_i=x,b_i=y\}\) 的大小,然后往右上方递推即可。
因为题目中要求 \(i<j\),所以最后减去 \(i=j\) 的方案数后除以二即可。
时间复杂度 \(O(n+AB)\)。其中 \(A=\max(a_i),B=\max(b_i)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=200010,M=2010,MOD=1e9+7;
int n,ans,a[N],b[N],f[2*M][2*M],g[2*M][2*M];

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i],&b[i]);
		f[M-a[i]][M-b[i]]++;
	}
	g[1][1]=1;
	for (int i=1;i<=4015;i++)
		for (int j=1;j<=4015;j++)
		{
			f[i][j]=(f[i][j]+f[i-1][j]+f[i][j-1])%MOD;
			g[i][j]=(g[i][j]+g[i-1][j]+g[i][j-1])%MOD;
		}
	for (int i=1;i<=n;i++)
	{
		ans=(ans+f[a[i]+M][b[i]+M])%MOD;
		ans=(ans+MOD-g[a[i]*2+1][b[i]*2+1])%MOD;
	}
	cout<<500000004LL*ans%MOD;
	return 0;
}
posted @ 2021-05-28 13:26  stoorz  阅读(43)  评论(0编辑  收藏  举报