传送门 to HDU
显然是要减去所有相交的路径。
考虑枚举最后一个相交的点,那么其前面可以乱走,后面必须不相交。
用 f ( y , x , Δ x ) f(y,x,\Delta x) f(y,x,Δx) 表示,从 ( 0 , y ) (0,y) (0,y) 走到 ( x , 0 ) (x,0) (x,0) 和 ( x + Δ x , 0 ) (x+\Delta x,0) (x+Δx,0) 的不相交——除了在起点 ( 0 , y ) (0,y) (0,y) 上相交——的路线数量。则
C x + y x C x + Δ x + y x + Δ x − ∑ 0 ≤ x 0 ≤ x ∑ 0 ≤ y 0 ≤ y ( C x 0 + y − y 0 x 0 ) 2 f ( y 0 , x − x 0 , Δ x ) = 0 C_{x+y}^{x}C_{x+\Delta x+y}^{x+\Delta x}-\sum_{0\le x_0\le x}\sum_{0\le y_0\le y}\left(C_{x_0+y-y_0}^{x_0}\right)^2 f(y_0,x-x_0,\Delta x)=0 Cx+yxCx+Δx+yx+Δx−0≤x0≤x∑0≤y0≤y∑(Cx0+y−y0x0)2f(y0,x−x0,Δx)=0
这个式子的意义是枚举最后一个相交的点。把 Δ x \Delta x Δx 换成 x 2 − x 1 x_2-x_1 x2−x1 ,把 x x x 换成 x 1 x_1 x1 ,把 x 0 x_0 x0 换成 x x x ,把 y 0 y_0 y0 换成 y y y ,把 y y y 换成 y 1 y_1 y1 ,我们有
∑ 0 ≤ x ≤ x 1 ∑ 0 ≤ y ≤ y 1 ( C x + y 1 − y x ) 2 f ( y , x 1 − x , x 2 − x 1 ) = C x 1 + y 1 x 1 C x 2 + y 1 x 2 \sum_{0\le x\le x_1}\sum_{0\le y\le y_1}(C_{x+y_1-y}^{x})^2f(y,x_1-x,x_2-x_1)=C_{x_1+y_1}^{x_1}C_{x_2+y_1}^{x_2} 0≤x≤x1∑0≤y≤y1∑(Cx+y1−yx)2f(y,x1−x,x2−x1)=Cx1+y1x1Cx2+y1x2
那么这道题中,我们需要计算
∑ 0 ≤ x ≤ x 1 ∑ 0 ≤ y ≤ y 1 C x + y 1 − y x C x + y 2 − y x f ( y , x 1 − x , x 2 − x 1 ) \sum_{0\le x\le x_1}\sum_{0\le y\le y_1}C_{x+y_1-y}^{x}C_{x+y_2-y}^{x}f(y,x_1-x,x_2-x_1) 0≤x≤x1∑0≤y≤y1∑Cx+y1−yxCx+y2−yxf(y,x1−x,x2−x1)
两个式子的形式挺相近的。但是我化简不动了。不过讲道理肯定是正确的式子。
考虑两条相交的路径。如果不考虑对应关系,它更像一个乱糟糟的毛线团——前面有两个端头,后面也有两个端头,中间搅在一块。
当然,我们可以先把毛线团的结构确定,然后再把颜色染上去。所以我们可以 交换对应关系。不难发现相交的路径数量就是 ( x 1 + y 2 y 2 ) ( x 2 + y 1 y 1 ) {x_1+y_2\choose y_2}{x_2+y_1\choose y_1} (y2x1+y2)(y1x2+y1) 。
#include
#include
#include
using namespace std;
typedef long long int_;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
inline void writeint(int x){
if(x > 9) writeint(x/10);
putchar((x%10)^48);
}
inline int qkpow(int_ b,int q,int m){
int ans = 1;
for(; q; q>>=1,b=b*b%m)
if(q&1) ans = ans*b%m;
return ans;
}
const int MaxN = 200005;
const int Mod = 1e9+7;
int jc[MaxN], inv[MaxN];
void prepare(){
jc[1] = inv[1] = 1;
for(int i=2; i<MaxN; ++i){
jc[i] = 1ll*jc[i-1]*i%Mod;
inv[i] = (0ll+Mod-Mod/i)*inv[Mod%i]%Mod;
}
for(int i=2; i<MaxN; ++i)
inv[i] = 1ll*inv[i]*inv[i-1]%Mod;
jc[0] = inv[0] = 1;
}
int_ C(int n,int m){
if(n < m) return 0; // 拿不出来
return 1ll*jc[n]*inv[m]%Mod*inv[n-m]%Mod;
}
int main(){
prepare();
for(int T=readint(); T; --T){
int x1 = readint(), x2 = readint();
int y1 = readint(), y2 = readint();
int_ all = C(x1+y1,y1)*C(x2+y2,y2)%Mod;
int_ bad = C(x1+y2,y2)*C(x2+y1,y1)%Mod;
all = (all+Mod-bad)%Mod;
printf("%lld\n",all);
}
return 0;
}