传送门

orz不会做。。。

一个好理解的做法(n^3*k):

分n=1和n=2两种情况考虑。

n=1时,预处理出前缀和sum[]。

设f[i][j]为到达第i格,已经放了j个子矩阵的最大和,

那么每次先把f[i][j]的值设为f[i-1][j](第i个元素不属于第j个子矩阵)

剩下的情况就是第i个元素属于第j个子矩阵了。

这时候用max(f[h-1][j-1]+(sum[i]-sum[h-1]), 1<=h<=i)更新f[i][j]的最大值,即枚举第j个子矩阵的起始点。

最终答案为f[m][k]。(边界条件为f[0][j]=0,包含空矩阵)

n=2时,预处理出分别列的前缀和sum1[],sum2[]。

设f[i][j][l]为在第1列到达第i格,第2列到达第j格,已经放了l个子矩阵的最大和,

那么每次先把f[i][j][l]的值设为max(f[i-1][j][l],f[i][j-1][l])(第i行第1列不属于子矩阵或第j行第2列不属于子矩阵,两者取较大值)

剩下的情况就是第i行第1列和第j行第2列都属于子矩阵了。

分两种情况:

一、第i行第1列和第j行第2列属于不同的子矩阵

分别枚举第i行第1列所在子矩阵的起始点和第j行第2列所在子矩阵的起始点并更新答案,

即用max(f[h-1][j][l-1]+(sum1[i]-sum1[h-1]), 1<=h<=i)和max(f[i][h-1][l-1]+(sum2[j]-sum2[h-1]),1<=h<=j)更新f[i][j]的最大值。

二、第i行第1列和第j行第2列属于同一子矩阵

仅当i==j时才包含这种情况(因为i和j要作为当前状态中子矩阵的末尾)。这时候这个子矩阵的列数必定为2。

还是一样枚举子矩阵的起始点,

在i==j的条件下用max(f[h-1][h-1][l-1]+(sum1[i]-sum1[h-1])+(sum2[j]-sum2[h-1]),1<=h<=i)更新答案。

最后答案为f[m][m][k](边界条件为f[0][0][l]=0,包含空矩阵)

#include <cstdio>
#define M 15
#define N 105
#define max(x, y) ((x) > (y) ? (x) : (y)) int n, m, K;
int sum[N][M];
int f[N][N][M], f0[N][M]; int main()
{
int i, j, k, l, x;
scanf("%d %d %d", &n, &m, &K);
for(i = 1; i <= n; i++)
for(j = 1; j <= m; j++)
{
scanf("%d", &x);
sum[i][j] = sum[i - 1][j] + x;
}
if(m == 1)
{
for(i = 1; i <= n; i++)
for(j = 1; j <= K; j++)
{
f0[i][j] = f0[i - 1][j];
for(k = 1; k <= i; k++)
f0[i][j] = max(f0[i][j], f0[k - 1][j - 1] + sum[i][1] - sum[k - 1][1]);
}
printf("%d\n", f0[n][K]);
return 0;
}
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
for(k = 1; k <= K; k++)
{
f[i][j][k] = max(f[i - 1][j][k], f[i][j - 1][k]);
for(l = 1; l <= i; l++)
f[i][j][k] = max(f[i][j][k], f[l - 1][j][k - 1] + sum[i][1] - sum[l - 1][1]);
for(l = 1; l <= j; l++)
f[i][j][k] = max(f[i][j][k], f[i][l - 1][k - 1] + sum[j][2] - sum[l - 1][2]);
if(i == j)
for(l = 1; l <= i; l++)
f[i][i][k] = max(f[i][i][k], f[l - 1][l - 1][k - 1] + sum[i][1] - sum[l - 1][1] + sum[i][2] - sum[l - 1][2]);
}
printf("%d\n", f[n][n][K]);
return 0;
}

  
还看到一个比较神的nk做法

O(Nk)时间复杂度0ms过

只有一列的不用说吧,我说下两列的

考虑每一行的状态

0 空出这一行

1 选择左边空出右边

2 选择右边空出左边

3 选择这一行两个(不作为一个矩阵,而是左边一列单独一个矩阵,右边单独一个矩阵)

4 选择这一行两个(两个一块作为一个矩阵的一部分)

定义f[i,j,k]为当前处理到第i行,已经选了j个矩阵,当前行状态为k的最大值(k为上面的0-4种状态)

如果空出这一行,则j不需要变化,直接继承上一行的各种状态的最大值

f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1],f[i-1][j][2],f[i-1][j][3],f[i-1][j][4]);

如果选择左边空出右边,如果上一行的左边没有单独地选择成为矩阵的话(即选择1或3),则j需要包含新选择成为的矩阵(即这一行的左边的这个矩阵),

如果上一行为同时选择两列的为一个矩阵的状态,则只选择单独的左边是不能包含进去上一行的矩阵的,所以也应j-1(t1为这一行左边的值)

f[i][j][1]=max(f[i-1][j-1][0],f[i-1][j][1],f[i-1][j-1][2],f[i-1][j][3], f[i-1][j-1][4])+t1;

右边同理(t2为这一行右边的值)

f[i][j][2]=max(f[i-1][j-1][0],f[i-1][j-1][1],f[i-1][j][2],f[i-1][j][3], f[i-1][j-1][4])+t2;

选择两个分别单独作为矩阵,类似只选择左边或右边,不过是单独选左边和右边合并了下

f[i][j][3]=max(f[i-1][j-1][1],f[i-1][j-1][2],f[i-1][j][3])+t1+t2;

if(j>=2) f[i][j][3]=max(f[i][j][3],f[i-1][j-2][4]+t1+t2);

选择两个作为一个矩阵,则上一行除了可以接上的,都得j-1

f[i][j][4]=max(f[i-1][j-1][0],f[i-1][j-1][1],f[i-1][j-1][2],f[i-1][j-1][3],f[i-1][j][4])+t1+t2;

[luoguP2331] [SCOI2005]最大子矩阵(DP)的更多相关文章

  1. BZOJ 1084: [SCOI2005]最大子矩阵 DP

    1084: [SCOI2005]最大子矩阵 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1084 Description 这里有一个n* ...

  2. 洛谷P2331 [SCOI2005]最大子矩阵 DP

    P2331 [SCOI2005]最大子矩阵 题意 : 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 第一行为n,m,k(1≤n≤ ...

  3. bzoj1084: [SCOI2005]最大子矩阵 dp

    这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 题解:m很小分类讨论,m==1时怎么搞都可以,m==2时,dp[i][j][k]表 ...

  4. 【BZOJ 1084】 1084: [SCOI2005]最大子矩阵 (DP)

    1084: [SCOI2005]最大子矩阵 Description 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. Input 第 ...

  5. bzoj千题计划198:bzoj1084: [SCOI2005]最大子矩阵

    http://www.lydsy.com/JudgeOnline/problem.php?id=1084 m=1: dp[i][j] 前i个数,选了j个矩阵的最大和 第i个不选:由dp[i-1][j] ...

  6. [Luogu 2331] [SCOI2005]最大子矩阵

    [Luogu 2331] [SCOI2005]最大子矩阵 题目描述 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 输入输出格式 ...

  7. 1084: [SCOI2005]最大子矩阵

    1084: [SCOI2005]最大子矩阵 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1325  Solved: 670[Submit][Stat ...

  8. BZOJ(6) 1084: [SCOI2005]最大子矩阵

    1084: [SCOI2005]最大子矩阵 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3566  Solved: 1785[Submit][Sta ...

  9. [bzoj1084][SCOI2005]最大子矩阵_动态规划_伪·轮廓线dp

    最大子矩阵 bzoj-1084 SCOI-2005 题目大意:给定一个n*m的矩阵,请你选出k个互不重叠的子矩阵使得它们的权值和最大. 注释:$1\le n \le 100$,$1\le m\le 2 ...

随机推荐

  1. lsattr

    -a  将隐藏文件的属性也显示出来 -R 连同子目录的数据也一并列出来 chattr +aij 文件名

  2. 超简单!一步创建自己的wifi热点~

    还在用某某卫士.某某管家创建wifi热点,甚至被忽悠专门买一个随身wifi吗?现在答案明确了:你完全用不着它们了.因为有更简单的方法. 只需要两个bat文件.一个用来启动wifi热点,另一个用来关闭w ...

  3. http协议参数详解

    整理一下http协议中的一些参数详解 截取了一个当前项目中的请求作为示例: Genaral:通用头 Request URL:当前请求的请求地址 Request Method:请求类型 get.post ...

  4. Django 表增加外键

    1.创建临时表,并把原表的数据复制到临时表 先根据python manage syl article查看创建临时表 CREATE TABLE `article_article_temp` ( `id` ...

  5. SQLITE-更新查询

    SQLite -更新查询 SQLite UPDATE查询用于修改现有表中的记录.您可以使用WHERE子句与更新查询更新选中的行,否则会被更新的所有行. 语法: UPDATE查询的WHERE子句的基本语 ...

  6. Gym 100342I Travel Agency (Tarjan)

    题意读懂了就好做了,就是求一下点双连通分量.维护一下一颗子树的结点数,对于一个结点当u是割点的时候, 统计一下u分割的连通分量v,每得到一个连通分量的结点数cnt(v)和之前连通分量结点数sum相乘一 ...

  7. UVA 11584 Partitioning by Palindromes 划分回文串 (Manacher算法)

    d[i]表示前面i个字符划分成的最小回文串个数, 转移:当第i字符加进来和前面区间j构成回文串,那么d[i] = d[j]+1. 要判断前面的字符j+1到i是不是回文串,可以用Manacher算法预处 ...

  8. selenium+chrome浏览器驱动-爬取百度图片

    百度图片网页中中,当页面滚动到底部,页面会加载新的内容. 我们通过selenium和谷歌浏览器驱动,执行js,是浏览器不断加载页面,通过抓取页面的图片路径来下载图片. from selenium im ...

  9. Codeforces Round #273 (Div. 2)-A. Initial Bet

    http://codeforces.com/contest/478/problem/A A. Initial Bet time limit per test 1 second memory limit ...

  10. mysql dump 参数大全

    Mysqldump参数大全   摘自:https://www.cnblogs.com/qq78292959/p/3637135.html 参数 参数说明 --all-databases  , -A 导 ...