Description
定义和谐矩阵为长不小于 Mina 且宽不小于 Minb 的矩阵,矩阵的权值为整个矩阵内所有数的和。给定一个长为 N
,宽为 M 的矩阵 A,求它的所有和谐子矩阵中权值第 K 小的矩阵,并输出它的权值。
Input
第 1 行为五个正整数,分别为 N , M , Mina , Minb , K,相邻两个数用一个空格分隔。接下来的 N 行,每行 M
个用一个空格分隔的数,表示给定的矩阵 A。
1 <= N,M <=1000, 1 <= Mina <= N, 1 <= Minb <= M,
1 <= K <= 250000 ,矩阵 A 内每个数均为不超过 3000 的非负整数
Output
仅一行,一个数,表示第 K 小矩阵的权值。如果第 K 小矩阵不存在,输出-1。
由于矩阵内整数非负,若子矩阵P包含子矩阵Q则sum(P)>sum(Q)
最小的子矩阵长宽一定为(Mina , Minb),从最小的矩阵开始向外bfs,每个子矩阵可以向上/下/左/右扩展一行/列,注意判重
用堆维护搜索顺序,散列表维护一个状态是否出现过,第k个出堆的子矩阵为答案
#include<cstdio> #include<cstdlib> #include<queue> const int P=2097152,R=10000000; char buf[R],*ptr=buf-1; inline int _int(){ int x=0,c=*++ptr; while(c<48)c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x; } int n,m,n1,m1,k; unsigned int s[1024][1024],rnd[1024][1024]; struct data{ unsigned int x1,y1,x2,y2,sum; data(){} inline data(int _x1,int _y1,int _x2,int _y2):x1(_x1),y1(_y1),x2(_x2),y2(_y2){ sum=s[x2][y2]+s[x1][y1]-s[x2][y1]-s[x1][y2]; } }w; inline bool operator<(const data&a,const data&b){ return a.sum>b.sum; } inline bool operator==(const data&a,const data&b){ return a.x1==b.x1&&a.y1==b.y1&&a.y2==b.y2&&a.x2==b.x2; } std::priority_queue<data>q; bool ins(data x){ static data xs[P]; static bool ed[P]; int w=rnd[x.x1][x.y1]^rnd[x.x2][x.y2]; while(ed[w]){ if(xs[w]==x)return 0; w+=12347; if(w>=P)w-=P; } xs[w]=x;ed[w]=1; return 1; } inline void push(data x){ if(ins(x))q.push(x); } int main(){ fread(buf,1,R-4,stdin); srand(1844677); n=_int();m=_int();n1=_int();m1=_int();k=_int(); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)s[i][j]=_int()+s[i][j-1],rnd[i][j]=(rand()^rand()<<10)&2097151; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)s[i][j]+=s[i-1][j]; for(int i=n1;i<=n;i++)for(int j=m1;j<=m;j++)push(data(i-n1,j-m1,i,j)); for(int i=0;i<k;i++){ if(q.empty()){ puts("-1"); return 0; } w=q.top();q.pop(); if(w.x1)push(data(w.x1-1,w.y1,w.x2,w.y2)); if(w.y1)push(data(w.x1,w.y1-1,w.x2,w.y2)); if(w.x2!=n)push(data(w.x1,w.y1,w.x2+1,w.y2)); if(w.y2!=m)push(data(w.x1,w.y1,w.x2,w.y2+1)); } printf("%u\n",w.sum); return 0; }