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;
}

猜你喜欢

转载自www.cnblogs.com/ckr1225/p/9489499.html