问题 B: 计数(组合数学+思维+线性求逆元)
题目描述
Alice和Bob在平面直角坐标系中下棋。Alice的棋子初始时在(0,0)位置,要走到(a,b)位置;Bob的棋子初始时在(c,0)位置,要走到(a,d)位置。棋子只能沿x轴或y轴正方向移动若干个单位长度,问有多少种移动方案使两颗棋子的移动路径不相交。
输入
输入一行4个正整数,依次为a,b,c,d。
输出
输出总方案数对质数 100000007 取模的结果。
样例输入 Copy
3 2 1 1
样例输出 Copy
6
提示
【样例解释】
A 走(0,0) → (0,2) → (3,2) 时, B 有 3 种走法:
(1,0) → (1,1) → (3,1)
(1,0) → (2,0) → (2,1) → (3,1)
(1,0) → (3,0) → (3,1)
A 走(0,0) → (0,1) → (1,1) → (1,2) → (3,2)时, B 有 2 种走法。
A 走(0,0) → (0,1) → (2,1) → (2,2) → (3,2)时, B 有 1 种走法。
A 走(0,0) → (0,2) → (3,2) 时, B 有 3 种走法:
(1,0) → (1,1) → (3,1)
(1,0) → (2,0) → (2,1) → (3,1)
(1,0) → (3,0) → (3,1)
A 走(0,0) → (0,1) → (1,1) → (1,2) → (3,2)时, B 有 2 种走法。
A 走(0,0) → (0,1) → (2,1) → (2,2) → (3,2)时, B 有 1 种走法。
【数据范围】
对于 50%的数据, a + b <= 20。
对于 70%的数据, a + b <= 2e4。
对于 100%的数据, a + b <= 2e5 且 a > c, b > d。
思路:记得做过。首先是A的终点在B的终点的上方。
如不考虑相交的话,答案即为C(a+b,a)*C(a+d-c,d)。考虑相交的情况,
交点只会出现再(c,0)-(a,d)的矩阵中,我们把彼此的终点换一下,这样就必然相交了。
再减去,C(a+d,a)*C(a+b-c,b)就是答案。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
using namespace std;
#define rep(i , a , b) for(register int i=(a);i<=(b);i++)
#define per(i , a , b) for(register int i=(a);i>=(b);i--)
#define ms(s) memset(s, 0, sizeof(s))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int , int> pi;
typedef unordered_map<int,int> un_map;
template<class T>
inline void read (T &x) {
x = 0;
int sign = 1;
char c = getchar ();
while (c < '0' || c > '9') {
if ( c == '-' ) sign = - 1;
c = getchar ();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar ();
}
x = x * sign;
}
const int maxn = 5e5+10;
const int inf = 0x3f3f3f3f;
const ll INF = ll(1e18);
const int mod = 100000007;
const double PI = acos(-1);
#define LOCAL
ll n,m;
ll f[maxn],inv[maxn];
void init() {
inv[0]=1;
inv[1]=1;
f[1]=1;
f[0]=1;
rep(i,2,maxn-5) {
f[i]=f[i-1]*i%mod;
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
rep(i,2,maxn-5) {
inv[i]=inv[i]*inv[i-1]%mod;
}
}
ll C(ll p,ll q) {
return f[p]*inv[q]%mod*inv[p-q]%mod;
}
int main(int argc, char * argv[])
{
init();
ll a,b,c,d;
read(a);read(b);read(c);read(d);
ll ans = (C(a+b,a)%mod*C(a+d-c,d)%mod-C(a+d,a)%mod*C(a+b-c,b)%mod+mod)%mod;
printf("%lld\n",ans);
return 0;
}