AGC001 E BBQ Hard
原问题等价于求
for i=1;i<n;i++
for j=i+1;j<=n;j++ do ans=ans+C(a[i]+a[j]+b[i]+b[j],a[i]+a[j])
显然这个式子是n^2的很不资瓷
我们发现a[i],b[i]都很小所以考虑组合性质优化
我们发现这个式子其实相当于求从(-ai,-bi)走到(aj,bj)的路径条数
直观的我们考虑建立超级源点S和超级汇点T
S向所有第三象限的点连边,T向所有第一象限的点连边求路径条数
所以我们可以dp出对于每一个(i,j)作为终点的方案数
然后dp[-a[i]][-b[i]]++,表示有一条从S过来的路径
答案就是枚举每一个i代表的点对(a[i],b[i])作为终点的方案数之和
注意减去自己到自己的方案数
代码如下:
#include<bits/stdc++.h> #define Mod 1000000007 #define N 500005 #define int long long #define invv (Mod+1)/2 using namespace std; int n,fac[N],inv[N],a[N],b[N],dp[4005][4005]; inline int ksm(int x,int y){int ans1=1;while (y){if (y&1) ans1=1ll*ans1*x%Mod;y>>=1;x=1ll*x*x%Mod; }return ans1;} inline int C(int n,int m){return 1ll*fac[n]*inv[m]%Mod*inv[n-m]%Mod;} signed main(){ scanf("%lld",&n);fac[0]=1; for (int i=1;i<=n;i++) scanf("%lld%lld",&a[i],&b[i]); for (int i=1;i<=8000;i++) fac[i]=1ll*fac[i-1]*i%Mod; inv[8000]=ksm(fac[8000],Mod-2); for (int i=7999;~i;i--) inv[i]=1ll*inv[i+1]*(i+1)%Mod; for (int i=1;i<=n;i++) dp[2000-a[i]][2000-b[i]]++; for (int i=0;i<=4000;i++){ for (int j=0;j<=4000;j++){ if (i) dp[i][j]=1ll*(dp[i][j]+dp[i-1][j])%Mod; if (j) dp[i][j]=1ll*(dp[i][j-1]+dp[i][j])%Mod; } }int ans=0; for (int i=1;i<=n;i++){ ans=1ll*(ans+dp[a[i]+2000][b[i]+2000])%Mod; ans=1ll*(ans-C(2*(a[i]+b[i]),2*a[i])+Mod)%Mod; } printf("%lld\n",1ll*ans*invv%Mod); return 0; }