hihocoder第238周:楊氏矩陣的個數
阿新 • • 發佈:2019-01-20
條件 tdi 公式 ++ http 鏈接 n! 元素 擴展歐幾裏得算法 $$
題目鏈接
問題描述
給定一個N行M列的矩陣,往裏面填入$1-N\times M
$個數字,使得這個矩陣每行、每列都滿足遞增。問:有多少種填法?
問題分析
這個問題很難,如果能夠直接想到,那就是天才了。
此問題中描述的矩陣就是楊氏矩陣的特例。楊氏矩陣又叫楊氏圖表。
楊氏圖表,它是這樣一個二維表,滿足條件:
(1)如果格子(i,j)沒有元素,則它右邊和上邊的相鄰格子也一定沒有元素。
(2)如果格子(i,j)有元素a[i,j],則它右邊和上邊的相鄰格子要麽沒有元素,要麽有元素且比a[i][j]大。
楊氏矩陣的計數公式為:
$$count=\frac{n!}{\sum_{x \in Grids}{hook(x)}}
其中$hook(x)
$表示格子x下方、右方的空白格點數(不包括它自己)之和+1。
關鍵方法
由楊氏矩陣的計數公式可知,此問題是一道數學題。關鍵在於模除運算,這可以通過擴展歐幾裏得算法求逆元來實現。
#include<stdio.h> #include<iostream> using namespace std; typedef long long ll; const int mod = 1e9 + 7; ll gcd(ll a, ll b, ll &x, ll &y) { if (b == 0) { x = 1, y = 0; return a; } ll q = gcd(b, a%b, y, x); y -= a / b * x; return q; } ll reverse(int v) { ll x, y; ll g = gcd(v, mod, x, y); return x; } int main() { int n, m; cin >> n >> m; ll s = 1; for (int i = 1; i <= n * m; i++) { s *= i; s %= mod; } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { int hook = n - i + m - j-1; int r = reverse(hook); s *= r; s %= mod; } } s = (s + mod) % mod; cout << s << endl; return 0; }
hihocoder第238周:楊氏矩陣的個數