[AGC001E]BBQ Hard-组合数学

来源:互联网 发布:钢管租赁软件下载 编辑:程序博客网 时间:2024/06/05 05:54

BBQ Hard

Problem Statement
Snuke is having another barbeque party.

This time, he will make one serving of Skewer Meal.

He has a stock of N Skewer Meal Packs. The i-th Skewer Meal Pack contains one skewer, Ai pieces of beef and Bi pieces of green pepper. All skewers in these packs are different and distinguishable, while all pieces of beef and all pieces of green pepper are, respectively, indistinguishable.

To make a Skewer Meal, he chooses two of his Skewer Meal Packs, and takes out all of the contents from the chosen packs, that is, two skewers and some pieces of beef or green pepper. (Remaining Skewer Meal Packs will not be used.) Then, all those pieces of food are threaded onto both skewers, one by one, in any order.

(See the image in the Sample section for better understanding.)

In how many different ways can he make a Skewer Meal? Two ways of making a Skewer Meal is different if and only if the sets of the used skewers are different, or the orders of the pieces of food are different. Since this number can be extremely large, find it modulo 109+7.

Constraints

2≦N≦200,000
1≦Ai≦2000,1≦Bi≦2000

Input

The input is given from Standard Input in the following format:

N
A1 B1
A2 B2
:
AN BN

Output

Print the number of the different ways Snuke can make a serving of Skewer Meal, modulo 109+7.

Sample Input 1

31 11 12 1

Sample Output 1

26

The 26 ways of making a Skewer Meal are shown below. Gray bars represent skewers, each with a number denoting the Skewer Meal Set that contained the skewer. Brown and green rectangles represent pieces of beef and green pepper, respectively.

ebbq


永远不要试图在无法优化空间复杂度的情况下卡空间。
因为你基本上是卡不动的。


思路:
很显然这就是在询问1i,jn,ij(ai+ajai+aj+bi+bj)

考虑把组合数描述成坐标。
那么这就是(ai,bi)(aj,bj) ,中途只能向上或向左走的路径条数。
考虑在坐标系上点上所有点,直接来一波dp算方案:
f[i][j]+=f[i1][j]+f[i][j1]
如果本来就有一个点就初始化那个点为1。

考虑这样算算重了自己的三象限坐标到自己一象限坐标的方案,所以要减去自己到自己的方案。
也就是说直接拿自己的组合数去减即可~
(组合数不能直接用递推形式因为会MLE)

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>using namespace std;const int md=1000000007;int fac[8009],inv[8009];int f[4005][4005];int a[200005];int b[200005];int ans,n;inline long long qpow(long long a,int b){    long long ret=1;    while(b)    {        if(b&1)            ret=ret*a%md;        a=a*a%md;        b>>=1;    }    return ret;}inline int c(int n,int m){    return 1ll*fac[n]*inv[m]%md*inv[n-m]%md;}int main(){    scanf("%d",&n);    for(int i=0;i<n;i++)    {        scanf("%d%d",a+i,b+i);        f[2001-a[i]][2001-b[i]]++;    }    for(int i=1;i<4002;i++)        for(int j=1;j<4002;j++)            f[i][j]=(f[i][j]+f[i-1][j]+f[i][j-1])%md;       fac[0]=1;    for(int i=1;i<=8002;i++)        fac[i]=1ll*fac[i-1]*i%md;    inv[8002]=qpow(fac[8002],md-2);    for(int i=8001;i>=0;i--)        inv[i]=1ll*inv[i+1]*(i+1)%md;    for(int i=0;i<n;i++)        ans=(ans+f[2001+a[i]][2001+b[i]])%md;    for(int i=0;i<n;i++)        ans=((ans-c((a[i]+b[i])<<1,b[i]<<1))%md+md)%md;    ans=(500000004ll*ans)%md;    printf("%d\n",ans);    return 0;}
原创粉丝点击