1. 程式人生 > 資訊 >拯救者 Y9000P v.s. R9000P:10 款遊戲 11 代酷睿平均領先 5%

拯救者 Y9000P v.s. R9000P:10 款遊戲 11 代酷睿平均領先 5%

題面傳送門
代數推導天地滅,組合意義保平安。
首先我們發現如果我們預處理組合數然後暴力計算是\(O(n^2)\)的很難優化。
我們考慮換一個思路。
我們知道\(C^{a_i+b_i}_{a_i}\)是從\((0,0)\)走到\((a_i,b_i)\)的方案數。
那麼原題目要求的就是\((-A_i,-B_i)\)走到\((A_j,B_j)\)的方案數。
這個東西很好算,我們設\(dp_{i,j}\)為點\((i,j)\)走到任意一個第三象限點的方案數,那麼就可以遞推計算。
注意減掉\(i=j\)再去重。時間複雜度\(O(Maxa\times Maxb+n)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 2000
#define M 200000
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,x[M+5],y[M+5],Maxx,Maxy;ll ans,G[N+5<<1][N+5<<1],frc[N+5<<2],inv[N+5<<2];
I ll mpow(ll x,int y=mod-2){ll ans=1;while(y) (y&1)&&(ans=ans*x%mod),x=x*x%mod,y>>=1;return ans;}
int main(){
	freopen("1.in","r",stdin);
	re int i,j;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]),Maxx=max(Maxx,x[i]+1),Maxy=max(Maxy,y[i]+1);
	for(i=1;i<=n;i++) G[Maxx-x[i]][Maxy-y[i]]++;frc[0]=inv[0]=1;for(i=1;i<=2*(Maxx+Maxy);i++) frc[i]=frc[i-1]*i%mod,inv[i]=inv[i-1]*mpow(i)%mod;
	for(i=1;i<=Maxx*2;i++)for(j=1;j<=Maxy*2;j++) G[i][j]=(G[i][j]+G[i-1][j]+G[i][j-1])%mod;for(i=1;i<=n;i++) ans+=G[x[i]+Maxx][y[i]+Maxy]-frc[(x[i]+y[i])*2]*inv[x[i]*2]%mod*inv[y[i]*2]%mod;
	printf("%lld\n",(ans%mod+mod)*mpow(2)%mod);
}