卧薪尝胆,厚积薄发。
矩阵
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;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡