题面:
思路:
首先,一个暴力的想法
对于每一对pack,求出f(ai+aj,bi+bj),其中f(x,y)=(x+y)!/(x!y!),也就是x个a,y个b的排列方式个数
然后转化模型,将f数组变化成这样的形式:f(x,y)表示一个x行y列的方格图,左下走到右上的方法数
然后将所有的f放到一个图中,就变成了:左下的n个点(-ai,-bi)到右上的n个点(ai,bi)的总方法数(任意一个出发任意一个到达)
用DAGdp把这个方法数求出来,就是sigma(f(ai+aj,bi+bj))(i=1...n,j=1...n),减去所有的f(ai+ai,bi+bi)再除以二即可
注意:MOD1e9+7意义下,要使用乘法逆元
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define ll long long 6 #define MOD 1000000007 7 using namespace std; 8 inline int read(){ 9 int re=0,flag=1;char ch=getchar(); 10 while(ch>'9'||ch<'0'){ 11 if(ch=='-') flag=-1; 12 ch=getchar(); 13 } 14 while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); 15 return re*flag; 16 } 17 const int dx[3]={0,0,1},dy[3]={0,1,0}; 18 ll dp[4020][4020];int N=2005;bool vis[4020][4020]; 19 int n,xx[200010],yy[200010],qx[200010],qy[200010],head=0,tail=1,maxq=200000; 20 ll inv[8010],finv[8010],f[8010]; 21 void init(){ 22 int i;inv[1]=finv[1]=1; 23 for(i=2;i<=8000;i++){ 24 inv[i]=((MOD-MOD/i)*inv[MOD%i])%MOD; 25 } 26 f[1]=1; 27 for(i=2;i<=8000;i++){ 28 f[i]=(f[i-1]*i)%MOD; 29 finv[i]=(finv[i-1]*inv[i])%MOD; 30 } 31 } 32 int main(){ 33 init(); 34 int i,maxx=0,maxy=0,x,y,tx,ty;ll X=0; 35 n=read(); 36 for(i=1;i<=n;i++){ 37 xx[i]=read();yy[i]=read(); 38 dp[N-xx[i]][N-yy[i]]+=1; 39 maxx=max(maxx,xx[i]);maxy=max(maxy,yy[i]); 40 } 41 qx[0]=N-maxx,qy[0]=N-maxy;vis[N-maxx][N-maxy]=1; 42 while(head!=tail){ 43 x=qx[head];y=qy[head];head=(head+1)%maxq; 44 // cout<<"dp "<<x<<ends<<y<<ends<<dp[x][y]<<endl;; 45 for(i=1;i<=2;i++){ 46 tx=x+dx[i];ty=y+dy[i]; 47 if(tx>N+maxx||ty>N+maxy) continue; 48 dp[tx][ty]=(dp[tx][ty]+dp[x][y])%MOD; 49 // cout<<" to "<<tx<<ends<<ty<<ends<<dp[tx][ty]<<endl; 50 if(!vis[tx][ty]){ 51 vis[tx][ty]=1; 52 qx[tail]=tx;qy[tail]=ty;tail=(tail+1)%maxq; 53 } 54 } 55 } 56 for(i=1;i<=n;i++){ 57 X=X+dp[N+xx[i]][N+yy[i]];X%=MOD; 58 X=X-((f[xx[i]*2+yy[i]*2]*finv[xx[i]*2])%MOD*finv[yy[i]*2])%MOD+MOD; 59 X%=MOD; 60 } 61 printf("%lld ",(X*inv[2])%MOD); 62 }