Codeforces 15D Map 单调队列+构造

来源:互联网 发布:挺进大别山 知乎 编辑:程序博客网 时间:2024/06/13 10:53

题目链接:http://codeforces.com/problemset/problem/15/D

题意:给定n*m的矩阵,每个点都是一个地基,上面的数字表示该地基的高度。

再给定a*b的小房子,要把a*b放在这个矩阵上,显然建房子要保证选取的地基高度一致。

若不一致,则要把选取的a*b大的矩阵中所有地基都挖低使得和其中一块最矮的地基高度一样,花费是挖的高度和

操作:

选取当前花费最小的一块矩阵,在上面建房子,若有多个方案花费一样,则优先选左上角的。

问:

建的房子的左上角坐标和建该房子的花费

思路:

显然我们要先求出选取每个点时,这个点的地基。用单调队列求一次行的,再在这基础上求一次列的就能得到这个点的地基。

然后把所有点都扔到堆里,跑出解即可。


双端队列的简单用法:

deque<int>q;

q.empty();

q.pop_front(); q.pop_back();

q.push_back(i); q.push_front(i);

单调队列:队尾->队首,队列中存的不是数组的元素,而是数组的下标

单调队列求最小就用递增,对于某一个数要求出这个数u到u+len-1的长度内的最小值:

对于i点,则要求出i点的最小值,我们不能直接求[ i, i+len-1]的值,而是求出[i-len+1, i]的最小值,然后转移到上述的 [u,u+len-1] 上

继续讨论对于i点在单调队列中的求解

1、则队尾元素必须是 [i-len+1,i]区间上的,所以 q.back()>=i-len+1,即->当{ q.back()+len-1<i } 时要把q.back()弹掉

2、要保持单调递增,所以当把这个元素x[i]加入队列时, q.front()必须<=x[i], 所以当 { q.front()>x[i] } 时要把q.front()弹掉

3、此时加入x[i],则此队列的数都在 [i-len+1,i]区间上且元素都是单调递增的,最小的元素是 x[q.back()]

4、显然x[i]的最小值就是 x[q.back()] ,到此计算出x[i]的最小值了

#include<stdio.h>#include<iostream>#include<string.h>#include<set>#include<vector>#include<map>#include<math.h>#include<queue>#include<string>#include<stdlib.h>#include<algorithm>using namespace std;#define N 1015#define LL __int64#define ll intll x[N], dou[N];void work(ll len, ll top){ deque<ll>q;// q.front() -> q.back()for(ll i = 1; i <= top; i++) {while(!q.empty() && q.front() + len <= i)q.pop_front();while(!q.empty() && x[i] <= x[q.back()]) q.pop_back();q.push_back(i);dou[i] = x[q.front()];}}ll n, m, a, b;struct node{ll x,y;LL val;node(ll a1=0,ll a2=0,LL a3=0):x(a1),y(a2),val(a3){}bool operator<(const node& Node) const{if(Node.val==val){if(Node.x==x) return Node.y<y;else return Node.x<x;}else return Node.val<val;}};priority_queue<node>q;vector<node>ans;bool use[N][N];void go(){ans.clear();while(!q.empty()){node u =q.top(); q.pop();if(use[u.x][u.y] || use[u.x+a-1][u.y+b-1] || use[u.x][u.y+b-1] || use[u.x+a-1][u.y])continue;ans.push_back(u);for(ll i = u.x; i < u.x+a; i++)for(ll j = u.y; j < u.y+b; j++)use[i][j] = 1;}ll siz = ans.size();printf("%d\n",siz);for(ll i = 0; i < siz; i++) printf("%d %d %I64d\n",ans[i].x,ans[i].y,ans[i].val);}ll val[N][N], mp[N][N];LL sum[N][N];int main(){ll i,j;while(~scanf("%d %d %d %d",&n,&m,&a,&b)) {for(i=1;i<=n;i++)for(j=1;j<=m;j++){scanf("%d",&mp[i][j]);sum[i][j] = (LL)mp[i][j] + sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];}for(i=1;i<=n;i++) {memcpy(x, mp[i], sizeof x);work(b, m);for(j=1;j<=m;j++) val[i][j] = dou[j];}for(i=b;i<=m;i++) {for(j=1;j<=n;j++) x[j] = val[j][i];work(a, n);for(j=1;j<=n;j++) val[j][i] = dou[j];}for(i=a; i<=n; i++)for(j=b;j<=m;j++)q.push(node(i-a+1,j-b+1,sum[i][j]-sum[i-a][j]-sum[i][j-b]+sum[i-a][j-b]-(LL)a*(LL)b*(LL)val[i][j]));go();}return 0;}


0 0
原创粉丝点击