1. 程式人生 > >2018黑龍江省賽 A Path Plan(組合數學 美妙的計數原理)

2018黑龍江省賽 A Path Plan(組合數學 美妙的計數原理)

7217: A Path Plan

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 66  解決: 31
[提交] [狀態] [討論版] [命題人:admin]

題目描述

WNJXYK hates Destinys so that he does not want to meet him at any time. Luckily, their classrooms and dormitories are at different places. The only chance for them to meet each other is on their way to classrooms from dormitories. 
To simple this question, we can assume that the map of school is a normal rectangular 2D net. WNJXYK’s dormitory located at (0,y_1) and his classroom located at (x_1,0). Destinys’s dormitory located at (0,y_2) and his classroom is located at (x_2,0). On their way to classrooms, they can do two kinds of movement : (x,y)→(x,y-1) and (x,y)→(x+1,y). 
WNJXYK does not want to meet Destinys so that he thinks that it is not safe to let his path to classroom from dormitory has any intersect point with Destinys ‘s. And then he wonders how many different paths for WNJXYK and Destinys arriving their classrooms from dormitories safely.

輸入

The input starts with one line contains exactly one positive integer T which is the number of test cases.
Each test case contains one line with four positive integers x1,x2,y1,y2 which has been explained above.

輸出

For each test case, output one line containing “y” where y is the number of different paths modulo 10^9+7.

樣例輸入

3
1 2 1 2
2 3 2 4
4 9 3 13

樣例輸出

3
60
16886100

提示


T≤1000
x1<x2,y1<y2
0 < x1,x2,y1,y2≤100000
For Test Case 1, there are following three different ways.

來源/分類

[提交] [狀態]

【題意】

如上圖所示,在方格的左邊緣給出兩個點,下邊緣給出兩個點。兩綠點之間連線,兩紅點之間連線,線路不能接觸,並且由下邊緣出發,僅能向左或向上走。問方案數

【分析】

若只考慮兩紅點連線(0,y),(x,0),一共要走y次豎邊,x次橫邊,故方案數為 (y+x)! / ( x! * y! ),即C(x+y,x)

假設先不考慮線路相交,則方案數為 C( y1+x1,x1 ) * C( y2+x2,x2 )

考慮線路相交,不妨把下邊緣的紅點綠點互換,則這時的連線必然相交,連好這對相交的線路,馬上把紅點綠點換回來,會發現,此時的線路就是原問題線路相交的方案。所以線路相交方案數=下邊緣紅綠點互換後的匯流排路數,即C( x1+y2,x1 ) * C( x2+y1,x2 )

上面兩方案數作差,即為不相交路線方案數。

【程式碼】

#include<bits/stdc++.h>
using namespace std;

const int mod=1e9+7;
const int MAX=2e5+5;
typedef long long ll;
ll inv(ll b){return b==1?1:(mod-mod/b)*inv(mod%b)%mod;}
ll fac[MAX],INV[MAX];
ll C(int n,int m)
{
    if(n<m)return 0;
    if(m==0||n==m)return 1;
    return fac[n]*INV[m]%mod*INV[n-m]%mod;
}

int main()
{
    fac[0]=1;
    for(int i=1;i<MAX;i++)fac[i]=fac[i-1]*i%mod;
    INV[MAX-1]=inv(fac[MAX-1]);
    for(int i=MAX-2;i;i--)INV[i]=INV[i+1]*(i+1)%mod;
    ll x,y,u,v;
    int T;
    cin>>T;
    while(T--)
    {
        cin>>x>>u>>y>>v;
        ll ans=C(y+x,x)*C(v+u,u)%mod-C(v+x,x)*C(y+u,u)%mod;
        ans=(ans%mod+mod)%mod;
        cout<<ans<<endl;
    }
}