Luogu_1565_牛宫_(最大子矩阵)

描述



http://www.luogu.org/problem/show?pid=1565

给出一个n*m的矩阵,求最大的且和值为正的子矩阵.

分析



很容易想到的是用前缀和维护,暴力枚举左上角和右下角,这样的复杂度是O(n^4)的.(虽然洛谷上这道题也能过)

一种神奇的方法:用前缀和记录每一行的前缀和.枚举的时候先枚举左右端点,然后分别算出左右端点之间每一行的和值,把一行看作一个单元(将一行压缩成一个点),求以行为单元的前缀和.然后前缀和相减可以得到子矩阵.而题目要求子矩阵的和值要为正,所以必须是值大的前缀和减值小的(相等不能减),所以把前缀和排个序.对于子矩阵t[i]-t[j](t是前缀和),t[i]必须大于t[j],而且t[i]代表的前缀和要尽可能"靠下",这样子矩阵才能尽可能大.所以我们排序后扫一遍前缀和,记录当前前缀和t[i]之前的(比t[i]大的)前缀和中最靠下的位置down,然后用down-t[i].id表示两个前缀和之差代表的子矩阵的高度(可能为负),记录最大高度h,最后乘以底边的长度(j-i+1)即可.

注意:

1.前缀和要加上0.

2.相同的不能相减,所以相同的前缀和把序号小的放在上面,这样减出来的就是负的.

 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4
 5 const int maxn=200+5;
 6 int n,m;
 7 ll ans;
 8 ll s[maxn][maxn];
 9
10 struct node{
11     ll x,id;
12     node(){}
13     node(ll x,ll id):x(x),id(id){}
14 }t[maxn];
15 bool cmp(node x,node y){
16     if(x.x==y.x) return x.id<y.id;
17     return x.x>y.x;
18 }
19 void solve(){
20     for(int i=1;i<=m;i++)
21         for(int j=i;j<=m;j++){
22             for(int k=1;k<=n;k++) t[k]=node(t[k-1].x+s[k][j]-s[k][i-1],k);
23             t[0]=node(0,0);
24             sort(t,t+n+1,cmp);
25             ll down=t[0].id,h=0;
26             for(int k=0;k<=n;k++){
27                 h=max(h,down-t[k].id);
28                 down=max(down,t[k].id);
29             }
30             ans=max(ans,h*(j-i+1));
31         }
32     printf("%lld\n",ans);
33 }
34 void init(){
35     scanf("%d%d",&n,&m);
36     for(int i=1;i<=n;i++)
37         for(int j=1;j<=m;j++){
38             int t; scanf("%d",&t);
39             s[i][j]=s[i][j-1]+t;
40         }
41 }
42 int main(){
43     init();
44     solve();
45     return 0;
46 }

时间: 2024-10-10 00:59:27

Luogu_1565_牛宫_(最大子矩阵)的相关文章

洛谷P1565 牛宫

洛谷P1565 牛宫 题目描述 AP 神牛准备给自己盖一座很华丽的宫殿.于是,他看中了一块N*M 的矩形空地. 空地中每个格子都有自己的海拔高度.AP 想让他的宫殿的平均海拔在海平面之上(假设 海平面的高度是0,平均数都会算吧?).而且,AP 希望他的宫殿尽量大,能够容纳更 多的人来膜拜他.请问AP 的宫殿最后会有多大? 输入输出格式 输入格式: 第一行为N 和M.之后N 行,每行M 个数,描述的空地的海拔. 输出格式: 输出一行,表示宫殿最大面积. 输入输出样例 输入样例: 3 24 0-10

【真题解】牛宫

.牛宫(long.pas/c/cpp)[问题描述]AP 神牛准备给自己盖一座很华丽的宫殿.于是,他看中了一块 N*M 的矩形空地.空地中每个格子都有自己的海拔高度.AP 想让他的宫殿的平均海拔在海平面之上(假设海平面的高度是 0,平均数都会算吧?) .而且,AP 希望他的宫殿尽量大,能够容纳更多的人来膜拜他.请问 AP的宫殿最后会有多大(宫殿必须是矩形)?[输入]第一行为 N和 M.之后 N 行,每行 M 个数,描述的空地的海拔(取值范围在 longint范围内).[输出]输出一行,表示宫殿最大

刷题_牛客_超级素数幂

1 import java.util.Scanner; 2 3 public class Main { 4 public static boolean isPrime(long m) { 5 if (m <= 1) 6 return false; 7 for (int i = 2; i * i < m; i++) { 8 if (m % i == 0) 9 return false; 10 } 11 return true; 12 } 13 14 public static void main

牛客_剑指offer_重建二叉树,再后续遍历_递归思想_分两端

   总结:    重建二叉树:其实就是根据前序和中序重建得到二叉树,得到后续,只要输出那边设置输出顺序即可 [编程题]重建二叉树 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. 完整通过代码: 先新建一个二叉树的类 public class TreeNode { int val; TreeNode left

刷题_牛客_字符串编码

给定一个字符串,请你将字符串重新编码,将连续的字符替换成"连续出现的个数+字符".比如字符串AAAABCCDAA会被编码成4A1B2C1D2A. 输入描述:每个测试输入包含1个测试用例,每个测试用例输入只有一行字符串,字符串只包括大写英文字母,长度不超过10000. 输出描述:输出编码后的字符串 输入例子:  AAAABCCDAA 输出例子:4A1B2C1D2A import java.util.Arrays; import java.util.Scanner; public clas

洛谷P3941入阵曲

洛谷P3941入阵曲 [题目描述] 丹青千秋酿,一醉解愁肠. 无悔少年枉,只愿壮志狂. 小 F 很喜欢数学,但是到了高中以后数学总是考不好. 有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识算法竞赛的 时候,觉得整个世界都焕然一新.这世界上怎么会有这么多奇妙的东西?曾经自己觉得难以 解决的问题,被一个又一个算法轻松解决. 小 F 当时暗自觉得,与自己的幼稚相比起来,还有好多要学习的呢. 一年过去了,想想都还有点恍惚. 他至今还能记得,某天晚上听着入阵曲,激动地睡不着觉,写题写到

Swfit 基本语句

// Playground - noun: a place where people can play import UIKit // swift语言没有Main 函数 ,main函数是封装在自己的框架里的 // 一行的注释用 // // 多行的注释,或者代码块 用 /* */ // 区别于OC中的 /* /* */ */ // println 是swift 1.2之前的;在swift 2.0 输出改为 print var str = "Hello, playground" // sw

数据库多级分类代码(MSSQL存储过程版)

说明 相信多级分类在任何一个信息系统中都会用到,网上也能找到很多版本,下面这个是基于MSSQL存储过程版的, 手上还有VB跟C#版的,不过这几年数据库一直用MSSQL,编程语言却从VBScript到C#又到PB, 搞到现在这套分类代码分别用VB.C#.PB实现了一遍,浪费了不少时间,NND神马多数据库啊!!!哥被忽悠了. 分类采用前缀编码的方式,编码使用字符串类型的,当然也有使用二进制实现的牛人^_^. 表结构说明(表Category,ClassId,ClassName,Code 为分类相关字段

Java 中很X的启动主键

生成工具:http://patorjk.com/software/taag/#p=testall&h=0&v=0&f=Graffiti&t=Type%20Something%20 如何修改spring boot 启动动画? 1.在resource 目录下创建 banner.txt 2.修改 banner.txt 内容 兔子 /*** * 瓦瓦 十 * 十齱龠己 亅瓦車己 * 乙龍龠毋日丶 丶乙己毋毋丶 * 十龠馬鬼車瓦 己十瓦毋毋 * 鬼馬龠馬龠十 己己毋車毋瓦 * 毋龠龠