【BZOJ1084】[SCOI2005]最大子矩阵【DP】
2016-04-15 22:42
459 查看
【题目链接】
终于A了这题了。
m = 1和m = 2两种情况分开做。
对于m = 1,很简单的DP。设dp[k]
表示前n个数字,分为k段的最大权值。
(1)不取第n个数,dp[k]
= dp[k][n - 1];
(2)取第n个数,并组成新的一段,dp[k]
= max{dp[k - 1][j] + sum
- sum[j]} (0 <= j < i)
注意j可以取到0。
对于m = 2,也是类似的。设dp[k]
[m]表示第一列到前n个数字,第二列到前m个数字,分为k个子矩阵的最大权值。
(1)不取第n个数或者不取第m个数,dp[k]
[m] = max{dp[k][n - 1][m], dp[k]
[m - 1]}
(2)第k个子矩阵是从第一列第n个数向上延伸的,dp[k]
[m] = max{dp[k - 1][i][m] + sum
[0] - sum[i][0]} (0 <= i < n),其中sum
[0]代表第一列的前缀和。
(3)第k个子矩阵是从第二列第m个数向上延伸的,dp[k]
[m] = max{dp[k - 1]
[j] + sum[m][1] - sum[j][1]} (0 <= j < m),其中sum[m][1]代表第二列的前缀和。
(4)当n == m时,第k个子矩阵从n和m同时向上延伸,dp[k]
[m] = max{dp[k - 1][i][i] + sum
[0] - sum[i][0] + sum[m][1] - sum[i][1]} (0 <= i < n)。
完啦。
/* Pigonometry */
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105, maxk = 12;
int n, m, k;
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
inline void solve1() {
static int sum[maxn], dp[maxk][maxn];
memset(sum, 0, sizeof(sum)); memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + iread();
for(int t = 1; t <= k; t++) for(int i = 1; i <= n; i++) {
dp[t][i] = dp[t][i - 1];
for(int j = 0; j < i; j++)
dp[t][i] = max(dp[t][i], dp[t - 1][j] + sum[i] - sum[j]);
}
printf("%d\n", dp[k]
);
}
inline void solve2() {
static int sum[maxn][2], dp[maxk][maxn][maxn];
memset(sum, 0, sizeof(sum)); memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++) {
sum[i][0] = sum[i - 1][0] + iread();
sum[i][1] = sum[i - 1][1] + iread();
}
for(int t = 1; t <= k; t++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) {
dp[t][i][j] = max(dp[t][i - 1][j], dp[t][i][j - 1]);
for(int l = 0; l < i; l++)
dp[t][i][j] = max(dp[t][i][j], dp[t - 1][l][j] + sum[i][0] - sum[l][0]);
for(int l = 0; l < j; l++)
dp[t][i][j] = max(dp[t][i][j], dp[t - 1][i][l] + sum[j][1] - sum[l][1]);
if(i == j) for(int l = 0; l < i; l++)
dp[t][i][j] = max(dp[t][i][j], dp[t - 1][l][l] + sum[i][0] - sum[l][0] + sum[j][1] - sum[l][1]);
}
printf("%d\n", dp[k]
);
}
int main() {
n = iread(); m = iread(); k = iread();
if(m == 1) solve1();
else if(m == 2) solve2();
return 0;
}
终于A了这题了。
m = 1和m = 2两种情况分开做。
对于m = 1,很简单的DP。设dp[k]
表示前n个数字,分为k段的最大权值。
(1)不取第n个数,dp[k]
= dp[k][n - 1];
(2)取第n个数,并组成新的一段,dp[k]
= max{dp[k - 1][j] + sum
- sum[j]} (0 <= j < i)
注意j可以取到0。
对于m = 2,也是类似的。设dp[k]
[m]表示第一列到前n个数字,第二列到前m个数字,分为k个子矩阵的最大权值。
(1)不取第n个数或者不取第m个数,dp[k]
[m] = max{dp[k][n - 1][m], dp[k]
[m - 1]}
(2)第k个子矩阵是从第一列第n个数向上延伸的,dp[k]
[m] = max{dp[k - 1][i][m] + sum
[0] - sum[i][0]} (0 <= i < n),其中sum
[0]代表第一列的前缀和。
(3)第k个子矩阵是从第二列第m个数向上延伸的,dp[k]
[m] = max{dp[k - 1]
[j] + sum[m][1] - sum[j][1]} (0 <= j < m),其中sum[m][1]代表第二列的前缀和。
(4)当n == m时,第k个子矩阵从n和m同时向上延伸,dp[k]
[m] = max{dp[k - 1][i][i] + sum
[0] - sum[i][0] + sum[m][1] - sum[i][1]} (0 <= i < n)。
完啦。
/* Pigonometry */
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105, maxk = 12;
int n, m, k;
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
inline void solve1() {
static int sum[maxn], dp[maxk][maxn];
memset(sum, 0, sizeof(sum)); memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + iread();
for(int t = 1; t <= k; t++) for(int i = 1; i <= n; i++) {
dp[t][i] = dp[t][i - 1];
for(int j = 0; j < i; j++)
dp[t][i] = max(dp[t][i], dp[t - 1][j] + sum[i] - sum[j]);
}
printf("%d\n", dp[k]
);
}
inline void solve2() {
static int sum[maxn][2], dp[maxk][maxn][maxn];
memset(sum, 0, sizeof(sum)); memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++) {
sum[i][0] = sum[i - 1][0] + iread();
sum[i][1] = sum[i - 1][1] + iread();
}
for(int t = 1; t <= k; t++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) {
dp[t][i][j] = max(dp[t][i - 1][j], dp[t][i][j - 1]);
for(int l = 0; l < i; l++)
dp[t][i][j] = max(dp[t][i][j], dp[t - 1][l][j] + sum[i][0] - sum[l][0]);
for(int l = 0; l < j; l++)
dp[t][i][j] = max(dp[t][i][j], dp[t - 1][i][l] + sum[j][1] - sum[l][1]);
if(i == j) for(int l = 0; l < i; l++)
dp[t][i][j] = max(dp[t][i][j], dp[t - 1][l][l] + sum[i][0] - sum[l][0] + sum[j][1] - sum[l][1]);
}
printf("%d\n", dp[k]
);
}
int main() {
n = iread(); m = iread(); k = iread();
if(m == 1) solve1();
else if(m == 2) solve2();
return 0;
}
相关文章推荐
- Oracle
- ListView之GeneralAdapter
- Node.js学习 - Route
- oracle表分区与索引分区
- Node.js学习 - Function
- 学习小结3
- C++ 中关于默认构造函数的一点困惑
- 剑指offer之编程(一)
- IntelliJ IDEA:Getting Started with Spring MVC, Hibernate and JSON实践
- Node.js学习 - Modules
- XCode-LibrarySearchPath和FramewrokSearchPath
- 函数调用的过程
- Invalid proguard configuration file path D:\...\proguard.cfg does not exist or is not a regular file
- iOS中通知中心的概念知识吧(objective - c版)
- Node.js学习 - Stream
- Node.js学习 - Buffer
- JAVA反射机制(及反射调用的性能简测)
- android之返回键与依次弹出返回栈
- VS 创建 使用C++ 静态类库(Dll)
- Java基础学习(三)—面向对象(上)