卧薪尝胆,厚积薄发。
矩阵
Date: Thu Nov 01 11:36:37 CST 2018
In Category:
NoCategory
Description:
给定一个长为
$N$
,宽为
$M$
的矩阵
$A$
,求它的所有长大于
$mina$
宽大于
$minb$
的子矩阵中中权值第
$K$
小的矩阵,并输出它的权值。
$1\leqslant n\leqslant 10^3,1\leqslant k\leqslant 250000$
Solution:
显然是一个类似超级钢琴那样的做法,即先把所有
$mina\times minb$
的矩阵放进堆里去,然后每次取出堆顶向四周扩展后再放回堆里,注意判重。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
#define R register
inline int rd()
{
R int res = 0,f = 1;
R char c = getchar();
while(!isdigit(c))
{
if(c == '-')f = -1;
c = getchar();
}
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res * f;
}
int n,m,mina,minb,k;
#define MAXN 1010
typedef long long ll;
int v[MAXN][MAXN];
ll s[MAXN][MAXN];
ll sum(int r1,int c1,int r2,int c2)
{
return s[r2][c2] - s[r1 - 1][c2] - s[r2][c1 - 1] + s[r1 - 1][c1 - 1];
}
struct state
{
int r1,c1,r2,c2;
ll v;
bool operator < (const state &b)const
{
if(v == b.v)
{
return (r1==b.r1?(c1==b.c1?(r2==b.r2?c2<b.c2:r2<b.r2):c1<b.c1):r1<b.r1);
}
return v > b.v;
}
};
map<state,bool> vis;
priority_queue<state> q;
void insert(int r1,int c1,int r2,int c2)
{
q.push((state){r1,c1,r2,c2,sum(r1,c1,r2,c2)});
return;
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&mina,&minb,&k);
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j)
v[i][j] = rd();
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j)
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + v[i][j];
for(int i = 1;i <= n - mina + 1;++i)
for(int j = 1;j <= m - minb + 1;++j)
insert(i,j,i + mina - 1,j + minb - 1);
state s;
for(int w = 1;w <= k;++w)
{
while(!q.empty() && vis[q.top()])q.pop();
s = q.top();q.pop();vis[s] = true;
int r1 = s.r1,c1 = s.c1,r2 = s.r2,c2 = s.c2;
if(r1 != 1)insert(r1 - 1,c1,r2,c2);
if(r2 != n)insert(r1,c1,r2 + 1,c2);
if(c1 != 1)insert(r1,c1 - 1,r2,c2);
if(c2 != m)insert(r1,c1,r2,c2 + 1);
}
cout << s.v << endl;
return 0;
}
In tag:
数据结构-堆
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡