题意
给你n个数对
(
a
i
,
b
i
)
(a_i,b_i)
(ai,bi),代表第i个包裹中两种物品分别有
a
i
,
b
i
a_i,b_i
ai,bi个。第i个包裹中有第i种针。
每次取两个包裹
i
,
j
i,j
i,j。那么一共有
a
i
+
a
j
a_i+a_j
ai+aj种物品1,有
b
i
+
b
j
b_i+b_j
bi+bj种物品2。将所有物品排成一列,串在i,j两个针上,形成一个烤串。询问有多少种靠串的类型,不同的针视为不同类型。
思路
也就是要求取
∑
i
=
1
n
∑
j
=
1
i
−
1
(
a
i
+
a
j
+
b
i
+
b
j
)
!
(
a
i
+
a
j
)
!
(
b
i
+
b
j
)
!
=
∑
i
=
1
n
∑
j
=
1
i
−
1
C
a
i
+
a
j
+
b
i
+
b
j
a
i
+
a
j
\sum_{i=1}^{n}\sum_{j=1}^{i-1}\frac{(a_i+a_j+b_i+b_j)!}{(a_i+a_j)!(b_i+b_j)!}=\sum_{i=1}^{n}\sum_{j=1}^{i-1}C_{a_i+a_j+b_i+b_j}^{a_i+a_j}
i=1∑nj=1∑i−1(ai+aj)!(bi+bj)!(ai+aj+bi+bj)!=i=1∑nj=1∑i−1Cai+aj+bi+bjai+aj
考虑两个问题:
- 给定n个0和m个1,问构成的01串的种类有多少种。
- 以(0,0)为起点,只能向上或向右走,问走到(n,m)的走法一共有多少种。
两个问题本质上是等价的。向右走可以等价成选一个0,向上可以等价为选一个1。两个问题的答案均是
C
n
+
m
n
C_{n+m}^{n}
Cn+mn。
原题的问题即是问题1,可以转化为第二种问题。即,选
(
a
i
,
b
i
)
(a_i,b_i)
(ai,bi)到
(
a
j
,
b
j
)
(a_j,b_j)
(aj,bj)可以看成二维平面上
(
−
a
i
,
−
b
i
)
(-a_i,-b_i)
(−ai,−bi)走到
(
a
j
,
b
j
)
(a_j,b_j)
(aj,bj)的路径数。
这样可以令所有
f
[
−
a
i
]
[
−
b
i
]
+
+
f[-a_i][-b_i]++
f[−ai][−bi]++(初始化)。最后答案就是
∑
f
[
a
i
]
[
b
i
]
\sum f[a_i][b_i]
∑f[ai][bi]。要去除自己走到自己的情况,即减去
∑
C
a
i
∗
2
+
a
j
∗
2
a
i
+
a
j
\sum C_{a_i*2+a_j*2}^{a_i+a_j}
∑Cai∗2+aj∗2ai+aj。然后每对点算了两次,还应该/2。
代码
//
// Created by yjq on 2019/10/23.
//
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ld long double
#define ull unsigned long long
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
const int N = 2010;
const int maxn = 2e5 + 10;
const ll mod = 1e9 + 7;
ll f[N * 3][N * 3], a[maxn], b[maxn], jie[maxn], ni[maxn];
ll pow_mod(ll a, ll b, ll m) {
ll ans = 1;
while (b) {
if (b & 1)ans = ans * a % m;
a = a * a % m;
b >>= 1;
}
return ans;
}
int main() {
__;
jie[0] = 1;
for (int i = 1; i < maxn; ++i) {
jie[i] = jie[i - 1] * (ll) i;
jie[i] %= mod;
}
ni[maxn - 10] = pow_mod(jie[maxn - 10], mod - 2, mod);
for (int i = maxn - 11; i >= 0; --i) {
ni[i] = ni[i + 1] * (ll) (i + 1) % mod;
}
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i] >> b[i];
f[N - a[i]][N - b[i]]++;
}
for (int i = 1; i <= N * 2; ++i) {
for (int j = 1; j <= N * 2; ++j) {
f[i][j] += f[i - 1][j] + f[i][j - 1];
f[i][j] %= mod;
}
}
ll ans = 0;
for (int i = 1; i <= n; ++i) {
ans += f[a[i] + N][b[i] + N];
ans = (ans - ((jie[a[i] * 2 + b[i] * 2] * ni[a[i] * 2]) % mod * ni[b[i] * 2]) % mod + mod + mod) % mod;
}
cout << (ans * ni[2]) % mod << endl;
return 0;
}