【agc001e】BBQ HARD(动态规划)
【agc001e】BBQ HARD(动态规划)
题面
题解
这些agc都是写的整场的题解,现在还是把其中一些题目单独拿出来发
这题可以说非常妙了。
我们可以把这个值看做在网格图上的一点\((-a[i],-b[i])\)走到\((a[j],b[j])\)的方案数。
而网格图走的方案数可以直接递推得到。
那么我们对于每个点把它的坐标取反到第三象限,然后对于整个坐标系计算走到每一个格子的总方案。
把所有\((a[i],b[i])\)的答案累加,再减去自己到自己的方案数,最后除二就是答案了。
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAX 200200
#define MOD 1000000007
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
const int py=2010;
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int a[MAX],b[MAX],n,ans;
int f[4500][4500];
int inv[9000],jc[9000],jv[9000];
int C(int n,int m){return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
int main()
{
n=read();
for(int i=1;i<=n;++i)a[i]=read(),b[i]=read();
for(int i=1;i<=n;++i)f[py-a[i]][py-b[i]]+=1;
for(int i=1;i<=py*2;++i)
for(int j=1;j<=py*2;++j)
add(f[i][j],f[i-1][j]),add(f[i][j],f[i][j-1]);
inv[0]=inv[1]=jc[0]=jv[0]=1;
for(int i=1;i<py<<2;++i)jc[i]=1ll*jc[i-1]*i%MOD;
for(int i=2;i<py<<2;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<py<<2;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
for(int i=1;i<=n;++i)add(ans,f[a[i]+py][b[i]+py]);
for(int i=1;i<=n;++i)add(ans,MOD-C(2*(a[i]+b[i]),2*a[i]));
ans=1ll*ans*inv[2]%MOD;printf("%d\n",ans);
return 0;
}