![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SM2E2M0MWZ0UTO3I2Y0IWN2EDMkhzN5I2MyY2YzIWZ58CX4AzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.png)
這個ai<=2000有點意思
啟發我們用O(W^2)的算法
FFT不存在,對應關系過緊
考慮組合意義轉化模組化,再進行分離
(除以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
*/