您的位置:首页 > 其它

【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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: