题意:
就是求$sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}inom{a_i+b_i+a_j+b_j}{a_i+b_i}$
$1leq nleq 200000$
$1leq a_i,b_ileq 2000$
题解:
这种题数据范围一看就是预处理答案,但是直接把和加起来的话复杂度依然是$n^2$的;
类似骗我呢那道题,可以考虑把组合数看成路径,那么上面的式子意思就是只能向右或向上走,从$(-a_i,-b_i)$走到$(a_j,b_j)$的方案数;
因为$a_i,b_i$都很小,所以可以直接dp出总的方案数:
$f[i][j]=f[i-1][j]+f[i][j-1]$
初始化时把$(-a_i,-b_i)$设为1即可;
统计答案时记得减去自己走到自己的方案数!
为了计算方便,我把所有坐标向右上平移了2000个单位。
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cmath>
5 #define mod 1000000007
6 #define inv_2 500000004
7 using namespace std;
8 typedef long long ll;
9 ll n,ans=0,a[200001],b[200001],f[4010][4010],inv[10001],jc[10001];
10 ll fastpow(ll x,ll y){
11 int ret=1;
12 for(;y;y>>=1,x=(ll)x*x%mod){
13 if(y&1)ret=(ll)ret*x%mod;
14 }
15 return ret;
16 }
17 void _(){
18 jc[0]=1;
19 for(int i=1;i<=10000;i++)jc[i]=(ll)jc[i-1]*i%mod;
20 inv[10000]=fastpow(jc[10000],mod-2);
21 for(int i=9999;i;i--)inv[i]=(ll)(i+1)*inv[i+1]%mod;
22 inv[0]=1;
23 }
24 int C(int n,int m){
25 return (ll)jc[n]*inv[m]%mod*inv[n-m]%mod;
26 }
27 int main(){
28 _();
29 memset(f,0,sizeof(f));
30 scanf("%d",&n);
31 for(int i=1;i<=n;i++){
32 scanf("%d%d",&a[i],&b[i]);
33 f[-a[i]+2001][-b[i]+2001]++;
34 }
35 for(int i=1;i<=4001;i++){
36 for(int j=1;j<=4001;j++){
37 f[i][j]=(f[i][j]+f[i][j-1]+f[i-1][j])%mod;
38 }
39 }
40 for(int i=1;i<=n;i++){
41 ans=(ans+f[a[i]+2001][b[i]+2001])%mod;
42 }
43 for(int i=1;i<=n;i++){
44 ans=(ans-C(a[i]*2+b[i]*2,a[i]*2)+mod)%mod;
45 }
46 //ans=ans/2%mod;
47 ans=(ll)ans*inv_2%mod;
48 printf("%d
",ans);
49 return 0;
50 }