1. 程式人生 > >HDU 6114 Chess【逆元+組合數】(組合數模板題)

HDU 6114 Chess【逆元+組合數】(組合數模板題)

模板題 tro 正整數 現在 ros 沒有 algo clas tdi

<題目鏈接>

題目大意:

車是中國象棋中的一種棋子,它能攻擊同一行或同一列中沒有其他棋子阻隔的棋子。一天,小度在棋盤上擺起了許多車……他想知道,在一共N×M個點的矩形棋盤中擺最多個數的車使其互不攻擊的方案數。他經過思考,得出了答案。但他仍不滿足,想增加一個條件:對於任何一個車A,如果有其他一個車B在它的上方(車B行號小於車A),那麽車A必須在車B的右邊(車A列號大於車B)。
現在要問問你,滿足要求的方案數是多少。

Input

第一行一個正整數T,表示數據組數。
對於每組數據:一行,兩個正整數N和M(N<=1000,M<=1000)。Output對於每組數據輸出一行,代表方案數模1000000007(1e9+7)。

Sample Input

1

1 1

Sample Output

1

解題分析:

其實仔細推敲這題之後,不難發現,由於n和m不一定想等,所以在棋盤中放置最多個數的車,並使其不攻擊,即求 C(max(n,m),min(n,m))。因為,假設n>m,即行數大於列數,此時要使棋盤中車盡可能的多,只能每一列都放一個車,而這m個車擺放的不同方案數即為在 n行中挑選出 m行來放這 m個車。所以,此題就很自然的轉化為了組合數的求解。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string
> #include<algorithm> #define ll long long using namespace std; const int mod = 1000000007; ll fast_pow(ll x, ll n) { ll ans = 1; while (n) { if (n & 1) ans = (ans*x) % mod; x = (x*x) % mod; n >>= 1; } return ans; } ll inv(ll a, ll p)
//費馬定理求a關於p的逆元 { return fast_pow(a, p - 2); } ll C(ll n, ll m) //求n中挑選m個的方案數 { ll ans = 1; for (ll i = n - m + 1; i <= n; i++) ans = (ans*i) % mod; for (ll i = 1; i <= m; i++) ans = (ans*inv(i, mod)) % mod; return ans; } int main() { int t; scanf("%d", &t); while (t--) { ll n, m; scanf("%lld%lld", &n, &m); printf("%lld\n", C(max(n, m), min(n, m))); } return 0; }

2018-08-12

HDU 6114 Chess【逆元+組合數】(組合數模板題)