天天看點

fzyzojP3782 -組合數問題

fzyzojP3782 -組合數問題
fzyzojP3782 -組合數問題

這個ai<=2000有點意思

啟發我們用O(W^2)的算法

FFT不存在,對應關系過緊

考慮組合意義轉化模組化,再進行分離

fzyzojP3782 -組合數問題
fzyzojP3782 -組合數問題

(除以2不需要逆元不懂為啥,但是算個逆元總不費事)

由于終點可能在起點的右下,是以,從左上到右下要再做一遍

但是每個終點正上方的起點統計了兩次,再減掉即可

(注意大力卡常:

1.s2[i][j]沒有,就不用算了

2.f,ans開long long 盡量減少取模

3.組合數用階乘計算

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=4000+4;
const int M=200000+5;
const int mod=1e9+7;
ll f[N][N];
int s1[N][N],s2[N][N];
int jie[N],inv[N];
int qm(int x,int y){
    int ret=1;
    while(y){
        if(y&1) ret=(ll)ret*x%mod;
        x=(ll)x*x%mod;
        y>>=1;
    }
    return ret;
}
ll mo1(ll x){
    return x>=4e12?x%mod:x;
}
ll mo2(ll x){
    return x>=0?x%mod:x;
}
int n;
int C(int n,int m){
    return (ll)jie[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
    rd(n);
    int a,b;
    jie[0]=1;
    for(reg i=1;i<=4000;++i) jie[i]=(ll)jie[i-1]*i%mod;
    inv[4000]=qm(jie[4000],mod-2);
    for(reg i=3999;i>=0;--i) inv[i]=(ll)inv[i+1]*(i+1)%mod;
    ll ans=0;
    for(reg i=1;i<=n;++i){
        rd(a);rd(b);
        int x=a-b+2000,y=b+2000;
        s1[x][y]++;
        x=-a+b+2000,y=-b+2000;
        s2[x][y]++;
        ans=mo2(ans+mod-C(2*a,2*b));
    }
    ans%=mod;
///    cout<<ans<<endl;
    for(reg i=4000;i>=1;--i){
        for(reg j=4000;j>=1;--j){
            f[i][j]=mo1(f[i+1][j]+f[i][j+1]+s1[i][j]);
            if(s2[i][j])ans=mo2(ans+(ll)f[i][j]*s2[i][j]);
        }
    }
    ans%=mod;
//    cout<<ans<<endl;
    for(reg i=1;i<=4000;++i){
        for(reg j=4000;j>=1;--j){
            f[i][j]=mo1(f[i-1][j]+f[i][j+1]+s1[i][j]);
            ans=s2[i][j]?(ans+(ll)f[i][j]*s2[i][j])%mod:ans;
            s1[i][j]+=s1[i][j+1];
            ans=s2[i][j]?(ans-(ll)s1[i][j]*s2[i][j]+(ll)10*mod)%mod:ans;
        }
    }
    ll inv2=5e8+4;
    ans=ans*inv2%mod;
    printf("%lld",ans);
    return 0;
}

}
signed main(){
    freopen("3782.in","r",stdin);
    freopen("3782.out","w",stdout);
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/8 18:52:17
*/