[map][堆]JZOJ 4754 矩阵
分析
我们可以用堆来维护所有的最小(指面积)矩阵
然后每次提出值最小的那个,对它进行扩张,将扩张后的的矩阵加入堆
提出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); } } } }
在日渐沉没的世界里,我发现了你。