【agc001e】BBQ HARD(动态规划)

【agc001e】BBQ HARD(动态规划)

题面

atcoder
洛谷

题解

这些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;
}
posted @ 2018-09-26 10:50  小蒟蒻yyb  阅读(645)  评论(0编辑  收藏  举报