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); } } } }