hdu5698 百度之星2016round2b第3题
这题首先是找规律推公式,然后就是组合数学的知识了。
题目是问到第n行第m列的格式有几种方案,我们可以用手算的方法列出当n和m比较小时的所有答案
比如我列出以下8*8的矩阵
924 462 210 84 28 7 1 0 462 252 126 56 21 6 1 0 210 126 70 35 15 5 1 0 84 56 35 20 10 4 1 0 28 21 15 10 6 3 1 0 7 6 5 4 3 2 1 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1
矩阵上的数表示从那个位置到最右下角一共有多少种方案。
求每个位置的值也简单,就是把它右下角的所有数加起来即可。
那么,把这个矩阵倒过来看,就是想要的结果矩阵了。
规律也很容易发现,首先,矩阵是对称的,所以我是只考虑m>=n的情况。
然后,可以发现每个位置的数就是一个组合数C(m + n - 4, n - 2)
最后就是求组合数取模了,C(m + n - 4, n - 2) %
然而,多年没做题的我,并不会组合数取模。找了以前的模板,是竹教主写的,看了好半天才明白,等我打完的时候,比赛刚结束。
比赛结束后交了一次,果然a了T_T
以下是代码
/* * baidu/win.cpp * Created on: 2016-5-22 * Author : ben */ #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <iostream> #include <algorithm> #include <queue> #include <set> #include <map> #include <stack> #include <string> #include <vector> #include <deque> #include <list> #include <functional> #include <numeric> #include <cctype> using namespace std; typedef long long LL; LL Ext_gcd(LL a, LL b, LL &x, LL &y) { if (b == 0) { x = 1, y = 0; return a; } LL ret = Ext_gcd(b, a % b, y, x); y -= a / b * x; return ret; } LL Inv(LL a, int m) { ///求除数a对m的逆元; LL d, x, y, t = (LL) m; d = Ext_gcd(a, t, x, y); if (d == 1) return (x % t + t) % t; return -1; } void work(int n, int m) { int i; const int mod = 1000000007; LL sum = 1; for (i = n - m + 1; i <= n; i++) { sum *= (LL) i; sum %= mod; } LL tmp = 1; for (i = 2; i <= m; i++) tmp *= i, tmp %= mod; sum *= Inv(tmp, mod); sum %= mod; printf("%I64d\n", sum); } int main() { int n, m; while (scanf("%d%d", &n, &m) == 2) { if (m < n) { int tmp = m; m = n; n = tmp; } work(m + n - 4, n - 2); } return 0; }