洛谷题目页面传送门 & CodeForces题目页面传送门

题意见洛谷里的翻译。(注意翻译里有错误,应该是优先选上面的矩阵,在同一行的优先选左边的矩阵)

这题一看就会做啊

(以下设大矩阵是\(n\times m\),小矩阵是\(n0\times m0\),第\(i\)行第\(j\)列高度为\(a_{i,j}\))

不难想到可以预处理出二维前缀和数组\(Sum\),后面就可以\(\mathrm{O}(1)\)求出一个小矩阵的和;然后跑\(2\)遍单调队列,第\(1\)次求出\(\forall i\in[1,n],\forall j\in[1,m-m0+1],mn1_{i,j}=\min\limits_{k=j}^{j+m0-1}\{a_{i,k}\}\),第二次求出\(\forall i\in[1,n-n0+1],\forall j\in[1,m-m0+1],mn2_{i,j}=\min\limits_{k=i}^{k+n0-1}\left\{\min\limits_{o=j}^{j+m0-1}\{a_{k,o}\}\right\}=\min\limits_{k=i}^{k+n0-1}\{mn1_{k,j}\}\)。那么一个左上角在\((i,j)\)的小矩阵的花费显然是\(Sum_{i+n0-1,j+m0-1}-Sum_{i-1,j+m0-1}-Sum_{i+n0-1,j-1}+Sum_{i-1,j-1}-n0\times m0\times mn2_{i,j}\)了。然后把所有小矩阵排个序,从头到尾扫一遍,如果一个小矩阵中有已经被标记的格子了,就不选;否则就选,并且把它所覆盖的格子都标记一下。但这样会TLE。不难想到,判一个小矩阵有没有被标记过的格子,只需要判四个角就可以了,这样判的时间总共就是\(\mathrm{O}(nm)\)了;而每个格子最多会被标记一次,所以标记总共也是\(\mathrm{O}(nm)\),这样就不会TLE了。(或者你用树状数组、线段树或其他一些更高级的数据结构我也不拦你)

对了,这题非常的卡常。我第一次交,T了。然后加了个快读,还是T了。然后把所有int改成register int,还是T了。最后我发现,原来计算一个小矩阵的花费虽然\(\mathrm{O}(1)\),但是常数略大,而我却把它放在sortcmp里计算,等于在扩大计算花费的常数(众所周知,快排里一个元素可能和多个元素比较)。于是我事先计算所有小矩阵的花费,然后存下来,cmp的时候直接调用,然后就AC了。

下面贴上蒟蒻又长又丑的代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define mp make_pair
#define X first
#define Y second
#define ri register int//呵呵
void read(int &x){//快读
x=0;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
}
const int N=1000,M=1000;
int n,m/*大矩阵的尺寸*/,n0,m0/*小矩阵的尺寸*/;
int a[N+1][M+1];//高度
int Sum[N+1][M+1];//二维前缀和
int q[N],head,tail;//单调队列
int mn1[N+1][M+1]/*一维最小值*/,mn2[N+1][M+1]/*二维最小值*/;
vector<pair<int,int> > ord;//小矩阵访问顺序
int cst[N+1][M+1];//小矩阵的花费
int calc_cst(int x,int y){//计算左上角在(x,y)的小矩阵的花费
return Sum[x+n0-1][y+m0-1]-Sum[x-1][y+m0-1]-Sum[x+n0-1][y-1]+Sum[x-1][y-1]-n0*m0*mn2[x][y];
}
bool cmp(pair<int,int> x,pair<int,int> y){//排序方式,以花费为第一关键字从小到大、行数为第二关键字从小到大、列数为第三关键字从小到大排序
return cst[x.X][x.Y]!=cst[y.X][y.Y]?cst[x.X][x.Y]<cst[y.X][y.Y]:x.X!=y.X?x.X<y.X:x.Y<y.Y;
}
bool vis[N+1][M+1];//标记
signed main(){
// freopen("C:\\Users\\chenx\\OneDrive\\桌面\\data.in","r",stdin);
read(n);read(m);read(n0);read(m0);
for(ri i=1;i<=n;i++)for(ri j=1;j<=m;j++){
read(a[i][j]);
Sum[i][j]=Sum[i-1][j]+Sum[i][j-1]-Sum[i-1][j-1]+a[i][j];//预处理二维前缀和
}
for(ri i=1;i<=n;i++){//第一次单调队列,算mn1
head=tail=0;
for(ri j=1;j<m0;j++){
while(head<tail&&a[i][q[tail-1]]>=a[i][j])tail--;
q[tail++]=j;
}
for(ri j=1;j+m0-1<=m;j++){
while(head<tail&&q[head]<j)head++;
while(head<tail&&a[i][q[tail-1]]>=a[i][j+m0-1])tail--;
q[tail++]=j+m0-1;
mn1[i][j]=a[i][q[head]];
}
}
// for(ri i=1;i<=n;i++){for(ri j=1;j+m0-1<=m;j++)cout<<mn1[i][j]<<" ";puts("");}puts("");
for(ri j=1;j+m0-1<=m;j++){//第二次单调队列,算mn2
head=tail=0;
for(ri i=1;i<n0;i++){
while(head<tail&&mn1[q[tail-1]][j]>=mn1[i][j])tail--;
q[tail++]=i;
}
for(ri i=1;i+n0-1<=n;i++){
while(head<tail&&q[head]<i)head++;
while(head<tail&&mn1[q[tail-1]][j]>=mn1[i+n0-1][j])tail--;
q[tail++]=i+n0-1;
mn2[i][j]=mn1[q[head]][j];
}
}
// for(ri i=1;i+n0-1<=n;i++){for(ri j=1;j+m0-1<=m;j++)cout<<mn2[i][j]<<" ";puts("");}
for(ri i=1;i+n0-1<=n;i++)for(ri j=1;j+m0-1<=m;j++)cst[i][j]=calc_cst(i,j)/*存花费*/,ord.pb(mp(i,j));
sort(ord.begin(),ord.end(),cmp);//排序
vector<pair<int,int> > ans;//答案序列
for(ri i=0;i<ord.size();i++){
int x=ord[i].X,y=ord[i].Y;
if(vis[x][y]||vis[x][y+m0-1]||vis[x+n0-1][y]||vis[x+n0-1][y+m0-1])continue;//判四个角
ans.pb(ord[i]);//放到答案序列里
for(ri j=x;j<=x+n0-1;j++)for(ri k=y;k<=y+m0-1;k++)vis[j][k]=true;//标记
}
cout<<ans.size()<<"\n";//输出选的小矩阵的个数
for(ri i=0;i<ans.size();i++)printf("%lld %lld %lld\n",ans[i].X,ans[i].Y,cst[ans[i].X][ans[i].Y]);//输出选的小矩阵
return 0;
}

CodeForces 15D Map的更多相关文章

  1. codeforces 15D . Map 优先队列

    题目链接 题目意思很简单nm的矩阵里, 选若干个ab的小矩阵, 定义每个矩阵的值为这个矩阵里的所有数的和-最小值*数的个数. 选小矩阵时, 优先选值最小的,然后次小的.. 知道不能选位置. 输出所有矩 ...

  2. 通过Jedis操作Redis

    package com.yh; import org.junit.After; import org.junit.Before; import org.junit.Test; import redis ...

  3. codeforces 651C(map、去重)

    题目链接:http://codeforces.com/contest/651/problem/C 思路:结果就是计算同一横坐标.纵坐标上有多少点,再减去可能重复的数量(用map,pair存一下就OK了 ...

  4. Codeforces Round #Pi (Div. 2) C. Geometric Progression map

    C. Geometric Progression Time Limit: 2 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/5 ...

  5. Codeforces 600 E. Lomsat gelral (dfs启发式合并map)

    题目链接:http://codeforces.com/contest/600/problem/E 给你一棵树,告诉你每个节点的颜色,问你以每个节点为根的子树中出现颜色次数最多的颜色编号和是多少. 最容 ...

  6. Codeforces Round #215 (Div. 2) B. Sereja and Suffixes map

    B. Sereja and Suffixes Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset ...

  7. Codeforces Beta Round #12 (Div 2 Only) D. Ball sort/map

    D. Ball Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/12/D D ...

  8. Educational Codeforces Round 2 E. Lomsat gelral 启发式合并map

    E. Lomsat gelral Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/600/prob ...

  9. Codeforces 1136D - Nastya Is Buying Lunch - [贪心+链表+map]

    题目链接:https://codeforces.com/problemset/problem/1136/D 题意: 给出 $1 \sim n$ 的某个排列 $p$,再给出若干 $(x,y)$ 表示当序 ...

随机推荐

  1. C++学习书籍推荐《More Exceptional C++》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <More Exceptional C++:40个新的工程难题.编程疑问及解决方法(中文版)>作为广为人知的<Exceptional C++ ...

  2. 生产Server遭挖矿程序入侵,暴力占用CPU

    区块链的火热,利益驱使必然导致不少PC或Server,被变成肉鸡,执行挖矿程序进行挖矿,进而导致我们正常的程序无法正常. (Centos7 Server)使用top命令查看服务器进程运行情况,发现几个 ...

  3. 常见Code Review过程中发现的问题

    软件环境:Spring MVC + MyBatis 主要体现在两个方面,一个是编码习惯问题,另一个是编码质量的问题.编码习惯主要有日志编写.代码注释以及编码风格的问题,而编码质量则与很多方面相关,比如 ...

  4. 预学第二天:计算机的基础知识+python安装+pycharm安装+思维导图

    目录 计算机的基础知识 计算机是由什么组成的 什么是操作系统

  5. Learning the Depths of Moving People by Watching Frozen

    基于双目的传统算法 对静止的物体, 在不同的 viewpoints 同一时刻进行拍摄, 根据拍摄到的结果, 使用三角测量算法计算出平面 2D 图像在 3D 图像中的坐标 单目 Ground Truth ...

  6. js深入之call、apply和bind

    一. call和apply 1. 代码完整实现 Function.prototype.mycall = function (context, ...argus) { if (typeof this ! ...

  7. nginx连接资源管理

    本文介绍在nginx中连接资源(即ngx_connection_t)的管理与使用. 连接池的初始化 在ngx_cycle_t结构体中维护了几个和连接相关的数据,具体如下 struct ngx_cycl ...

  8. Spring Boot 面试的十个问题

    用下面这些常见的面试问题为下一次 Spring Boot 面试做准备. 在本文中,我们将讨论 Spring boot 中最常见的10个面试问题.现在,在就业市场上,这些问题有点棘手,而且趋势日益严重. ...

  9. linuk相关命令

    1,Linux的每个文件一般都有三个权限 r--读,w--写,x--执行,其分别对应的数值为4,2,1. 输入ll可以查看到文件的权限. 2,给目录或文件授权 chmod 777 目录名 chmod ...

  10. DotSpatial安装、类库引用方法

    解决VS工具栏添加DotSpatial后,控件不全问题. 注意注意注意:不要使用Nuget安装DotSpatial!!! 我在Nuget上把所有DotSpatial的版本都安装了一遍,都缺少控件,然后 ...