【0611dp练习赛】gugu
题目
给定一个大小为\(N × M\)的矩形网格,每个格点用一个坐标\((x, y)\)描述,这里满 足\(1 ≤ x ≤ N\)且\(1 ≤ y ≤ M\)。定义一个合法的路径同时满足如下条件:
(1) 路径的起点是\((1,1)\),终点是\((N, M)\);
(2) 到达一个点之后,只能往横坐标和纵坐标中有且仅有一个增加了\(1\)的点走。即\((x, y)\)只能走到\((x + 1, y)\)或\((x, y + 1)\);
(3) 满足\(T\)个限制,每个限制都形如:如果走到了\((a, b)\)那么下一步一定要走到\((c, d)\)。这里可能会有\(a = N, b = M\)的情况,不管就好了。 求有多少条合法的路径。
由于答案可能很大,请输出其对\(10^9 + 7\)取模的结果。
Solution
经过亲身被卡经历得出\((c, d)\)的所有取值情况
\((a, b)\)(a,b从一开始就不会被走进)
\((a + 1, b)\)(右边的格将收不到左边的贡献)
\((a, b + 1)\)(下面的格将收不到上面的贡献)
直接\(nm\)计算贡献,对于特殊点特殊处理就好了。
\(\mathrm{Code:}\)
#include <bits/stdc++.h>
const int mod = 1000000007;
const int N = 3010;
const int T = 1000010;
int n, m, t;
inline int add(int a, int b) { return a + b >= mod ? a + b - mod : a + b; }
inline void Add(int& a, int b) {
a = add(a, b);
return void();
}
int f[N][N], v[N][N];
inline int read() {
int s = 0, w = 1;
char c = getchar();
while ((c < '0' || c > '9') && c != '-') c = getchar();
if (c == '-') w = -1, c = getchar();
while (c <= '9' && c >= '0')
s = (s << 1) + (s << 3) + c - '0', c = getchar();
return s * w;
}
template <class T>
inline void write(T x) {
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
return void();
}
signed main() {
// freopen("gugu.in", "r", stdin);
// freopen("gugu.out", "w", stdout);
n = read();
m = read();
t = read();
memset(v, 0, sizeof(v));
for (int i = 1; i <= t; ++i) {
int _a = read(), _b = read(), _c = read(), _d = read();
if (_c == _a + 1) v[_a][_b + 1] += 1;
if (_d == _b + 1) v[_a + 1][_b] += 2;
if (_c == _a && _b == _d) v[_a][_b + 1] += 1, v[_a + 1][_b] += 2;
}
f[1][1] = 1;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
if (i == 1 && j == 1) continue;
int tmp = 0;
if (v[i][j] == 1) Add(tmp, f[i - 1][j]);
if (v[i][j] == 2) Add(tmp, f[i][j - 1]);
if (v[i][j] == 0) Add(tmp, f[i][j - 1]), Add(tmp, f[i - 1][j]);
f[i][j] = tmp;
}
write(f[n][m]);
putchar(10);
return 0;
}
EX
其实我觉得这种题正式比赛中不会出现吧。
毕竟题意模棱两可完全考验理解的时候不会很多。
我是真的感到恶心。