HUT-1943 黑箱
直接用DP方程直接TLE了,因为数据范围达到了10^9......
这题的正解是先用DP方程分别求出在t步走到每一行(列)的可能,再将其相加到一个步数为t的数组中,表示到第t步时,所有行(列)的种数,最后再用一个组合公式,将规定的K步进行分解来求得最后的答案。这题要特别要注意边界条件,还有就是防止溢出。这里用到了一个公式来求组合数 C[i, j] = C[i-1, j] + C[i-1, j-1]。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #define MOD 1000000007 using namespace std; int N, M, K, x, y; int C[1005][1005], _r[1005][1005], _c[1005][1005]; int kr[1005], kc[1005]; void pre() { for (int i = 0; i <= 1000; ++i) { C[i][0] = 1; for (int j = 1; j <= i; ++j) { C[i][j] = (C[i-1][j] + C[i-1][j-1]) % MOD; /* printf("%d %d %d\n", i, j, C[i][j]); getchar(); */ } } } void add() { } void go() { memset(_r, 0, sizeof (_r)); memset(_c, 0, sizeof (_c)); memset(kr, 0, sizeof (kr)); memset(kc, 0, sizeof (kc)); _r[0][x] = 1, _c[0][y] = 1; for (int t = 1; t <= K; ++t) { // printf("t = %d, N = %d\n", t, N); for (int i = 1; i <= N; ++i) { if (i - 1 >= 1) { _r[t][i-1] += _r[t-1][i]; // printf("%d %d %d\n", t, i-1, _r[t][i-1]); _r[t][i-1] %= MOD; } if (i + 1 <= N) { _r[t][i+1] += _r[t-1][i]; // printf("%d %d %d\n", t, i+1, _c[t][i+1]); _r[t][i+1] %= MOD; } } for (int j = 1; j <= M; ++j) { if (j - 1 >= 1) { _c[t][j-1] += _c[t-1][j]; _c[t][j-1] %= MOD; } if (j + 1 <= M) { _c[t][j+1] += _c[t-1][j]; _c[t][j+1] %= MOD; } } } for (int t = 0; t <= K; ++t) { for (int i = 1; i <= N; ++i) { kr[t] += _r[t][i]; // 把每个步数下走到所有可能相加 kr[t] %= MOD; } for (int j = 1; j <= M; ++j) { kc[t] += _c[t][j]; kc[t] %= MOD; } } } int deal() { int ans = 0; for (int i = 0; i <= K; ++i) { ans += (long long)C[K][i] * kr[i] % MOD * kc[K-i] % MOD; ans %= MOD; } return ans % MOD; } int main() { pre(); int T; scanf("%d", &T); while (T--) { scanf("%d %d %d %d %d", &N, &M, &K, &x, &y); go(); printf("%d\n", deal()); } return 0; }