题意:
有n个背包,第i个背包里有一个编号为i的棍子、Ai个肉和Bi个菜。任选两个不同的背包,把这两个背包里所有的肉和菜都用这两根棍子串起来形成一个烤串,问能串出多少种烤串。
当且仅当至少有一根棍子的编号不同,或者是肉和菜的数目不同或者是排列方式不同时,称这两种烤串是不同的。
一个比较显然的暴力:枚举2个背包,然后求出 ,但对于这种数据范围显然不够。
那我们考虑一下这个式子有什么几何意义。
好像是从
到
的方案数?
说明:从
到
需要
步,其中有
步往水平方向走。
那么就可以dp了,dp[i][j]为从左下角到(i,j)的方案数,cnt[i][j]为落在(i,j)上的点的个数。
显然是从左边和下面转移过来的,所以不多说。
最后答案就成了
。
然后发现多算了自己到自己的情况,要减掉。
最后结果除以2.(我也不清楚为什么…反正某题解是这样做的QAQ有哪位dalao可以解释吗)
被注释掉的就是暴力代码。
#include<cstdio>
#define mod 1000000007
#define maxn 200005
#define N 2000
int n,fact[N*4+5],inv[N*4+5],ans,cnt[N*2+5][N*2+5],dp[N*2+5][N*2+5],inv2;
void init()
{
fact[0]=1;
for(int i=1;i<=N*4;i++) fact[i]=1ll*fact[i-1]*i%mod;
inv[1]=1;
for(int i=2;i<=N*4;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
inv[0]=1,inv2=inv[2];
for(int i=1;i<=N*4;i++) inv[i]=1ll*inv[i-1]*inv[i]%mod;
}
int F(int a,int b) { return 1ll*fact[a+b]*inv[a]%mod*inv[b]%mod; }
int main()
{
scanf("%d",&n);
init();
for(int i=1;i<=n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
cnt[N+a][N+b]++,dp[N-a][N-b]++;
ans=(ans+mod-F(a*2,b*2))%mod;
}
for(int i=0;i<=N*2;i++)
for(int j=0;j<=N*2;j++)
{
if(i) dp[i][j]+=dp[i-1][j];
if(j) dp[i][j]+=dp[i][j-1];
dp[i][j]%=mod;
ans=(ans+1ll*dp[i][j]*cnt[i][j]%mod)%mod;
}
/*for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
ans=(ans+F(a[i]+a[j],b[i]+b[j]))%mod;*/
printf("%lld\n",1ll*ans*inv2%mod);
}