【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;
}