BZOJ 3997 [TJOI 2015 组合数学] 解题报告
这个题我脑洞了一个结论:
首先,我们定义满足以下条件的路径为“从右上到左下的路径”:
对于路径上任何不相同的两个点 $(x_1, y_1)$,$(x_2, y_2)$,都有:
- $x_1\neq x_2, y_1\neq y_2$
- 若 $x_1 > x_2$,则有 $y_1 < y_2$;否则当 $x_1 < x_2$ 时, $y_1 > y_2$。
然后我们找到所有从右上到左下的路径,其中路径的权值和最大的那条路径的权值和就是答案了。
然后我们就可以用 Dp 解决问题了。
我们可以把每一行都翻转一下,那么就可以有:
$$Dp[i][j] = max(Dp[i - 1][j - 1] + W[i][j], Dp[i - 1][j], Dp[i][j - 1])$$
其中 $W[i][j]$ 为这个格子的权值,那么答案就是 $Dp[n][m]$ 了。
至于为什么是对的。。。我也不太清楚。。。反正感觉好像是对的。。。而且也过了。。。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 #define N 1000 + 5 8 9 int n, m, ans; 10 int Map[N][N], Dp[N][N]; 11 12 inline int getint() 13 { 14 char ch = '\n'; 15 for (; ch > '9' || ch < '0'; ch = getchar()) ; 16 int res = ch - '0'; 17 for (ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar()) 18 res = (res << 3) + (res << 1) + ch - '0'; 19 return res; 20 } 21 22 inline void Solve() 23 { 24 n = getint(), m = getint(); 25 for (int i = 1; i <= n; i ++) 26 for (int j = m; j; j --) 27 Map[i][j] = getint(); 28 for (int i = 1; i <= n; i ++) 29 for (int j = 1; j <= m; j ++) 30 { 31 Dp[i][j] = Dp[i - 1][j - 1] + Map[i][j]; 32 Dp[i][j] = max(Dp[i][j], Dp[i - 1][j]); 33 Dp[i][j] = max(Dp[i][j], Dp[i][j - 1]); 34 } 35 ans = Dp[n][m]; 36 } 37 38 int main() 39 { 40 #ifndef ONLINE_JUDGE 41 freopen("3997.in", "r", stdin); 42 freopen("3997.out", "w", stdout); 43 #endif 44 45 for (int _ = getint(); _; _ --) 46 { 47 Solve(); 48 printf("%d\n", ans); 49 } 50 51 #ifndef ONLINE_JUDGE 52 fclose(stdin); 53 fclose(stdout); 54 #endif 55 return 0; 56 }