[map][堆]JZOJ 4754 矩阵

Description
 
Input
Output
 
Sample Input
输入1:
3 4 2 2 3
0 1 3 7
1 16 5 2
7 6 9 3

输入2:
7 7 3 4 13
5 5 7 8 6 8 5
8 4 6 6 3 4 2
8 0 9 2 3 4 7
8 5 4 5 3 9 8
0 3 0 6 0 3 8
9 7 1 8 8 9 4
7 8 4 5 7 6 1
Sample Output
输出1:
19

输出2:
58

 
Data Constraint

分析

我们可以用堆来维护所有的最小(指面积)矩阵

然后每次提出值最小的那个,对它进行扩张,将扩张后的的矩阵加入堆

提出k次即为答案

注意判重,可以用map

 

#pragma GCC optimize(2)
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
typedef pair<ii,ii> iiii;
const int N=1e3+10;
struct Rect {
    ll sum;
    int x1,y1,x2,y2;
    friend bool operator < (Rect a,Rect b) {
        return a.sum<b.sum;
    }
};
map<iiii,bool> M;
Rect a[2000010];
ll s[N][N];
int n,m,ma,mb,k,sz;

void Delete() {
    a[1]=a[sz];sz--;
    int x=1;
    while (x<sz) {
        if ((x<<1)<=sz) {
            if ((x<<1)+1<=sz)  {
                if (a[x]<a[x<<1]&&a[x]<a[(x<<1)+1]) break;
                if (a[x<<1]<a[(x<<1)+1]) swap(a[x],a[x<<1]),x=x<<1;
                else swap(a[x],a[(x<<1)+1]),x=(x<<1)+1;
            }
            else {
                if (a[x]<a[x<<1]) break;
                swap(a[x],a[x<<1]);x=x<<1;
            }
        }
        else break;
    }
}

void Insert(Rect x) {
    a[++sz]=x;
    int y=sz;
    while (y>0) {
        if (a[y]<a[y>>1]) {
            swap(a[y],a[y>>1]);
            y=y>>1;
        }
        else break;
    }
}

ll SUM(int x1,int y1,int x2,int y2) {
    return s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
}

int main() {
    scanf("%d%d%d%d%d",&n,&m,&ma,&mb,&k);
    int i,j;
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++)
            scanf("%lld",&s[i][j]),s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
    for (i=1;i<=n-ma+1;i++)
        for (j=1;j<=m-mb+1;j++) Insert((Rect){SUM(i,j,i+ma-1,j+mb-1),i,j,i+ma-1,j+mb-1});

    while (k--) {
        Rect r=a[1],u;Delete();
        if (k==0) {
            printf("%lld\n",r.sum);
            return 0;
        }
        if (r.x2<n) {
            u=r;
            u.x2++;u.sum+=SUM(u.x2,u.y1,u.x2,u.y2);
            if (!M[make_pair(make_pair(u.x1,u.y1),make_pair(u.x2,u.y2))]) {
                M[make_pair(make_pair(u.x1,u.y1),make_pair(u.x2,u.y2))]=1;
                Insert(u);
            }
        }
        if (r.y2<m) {
            u=r;
            u.y2++;u.sum+=SUM(u.x1,u.y2,u.x2,u.y2);
            if (!M[make_pair(make_pair(u.x1,u.y1),make_pair(u.x2,u.y2))]) {
                M[make_pair(make_pair(u.x1,u.y1),make_pair(u.x2,u.y2))]=1;
                Insert(u);
            }
        }
    }
}
View Code

 

转载于:https://www.cnblogs.com/mastervan/p/10574731.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值