AT1983 [AGC001E] BBQ Hard
题面传送门
代数推导天地灭,组合意义保平安。
首先我们发现如果我们预处理组合数然后暴力计算是\(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);
}