bzoj4716假摔

bzoj4716假摔

题意:

给出一个矩阵,求这个矩阵中权值和第k小的长在xmin到n之间,宽在ymin到m之间的子矩阵。n,m≤1000,k≤250000。

题解:

首先求出长为xmin,宽为ymin的子矩阵放入优先队列,每次取出时如果该矩阵之前没有出现过(用set判重),则将其扩展并放入优先队列,输出第k个不重复的(这里指位置不重复的,权值可以相等)。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #include <set>
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define maxn 1010
 8 using namespace std;
 9 
10 inline int read(){
11     char ch=getchar(); int f=1,x=0;
12     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
13     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
14     return f*x;
15 }
16 int sum[maxn][maxn],n,m,xmin,ymin,k,tot;
17 struct nd{
18     int x,y,l,c,v;
19     bool operator < (const nd &a)const{
20         if(v!=a.v)return v>a.v; if(x!=a.x)return x<a.x; if(y!=a.y)return y<a.y;
21         if(l!=a.l)return l<a.l; return c<a.c;
22     };
23 };
24 priority_queue<nd>q; set<nd>st;
25 int main(){
26     n=read(); m=read(); xmin=read(); ymin=read(); k=read();
27     inc(i,1,n)inc(j,1,m){int x=read(); sum[i][j]=sum[i-1][j]-sum[i-1][j-1]+sum[i][j-1]+x;}
28     inc(i,1,n-xmin+1)inc(j,1,m-ymin+1){
29         q.push((nd){i,j,xmin,ymin,sum[i+xmin-1][j+ymin-1]-sum[i+xmin-1][j-1]-sum[i-1][j+ymin-1]+sum[i-1][j-1]});
30     }
31     while(!q.empty()){
32         nd x=q.top(); q.pop(); if(st.find(x)!=st.end())continue;
33         tot++; if(tot==k){printf("%d",x.v+1); break;} st.insert(x);
34         if(x.x+x.l<=n)
35             q.push((nd){x.x,x.y,x.l+1,x.c,sum[x.x+x.l][x.y+x.c-1]-sum[x.x+x.l][x.y-1]-sum[x.x-1][x.y+x.c-1]+sum[x.x-1][x.y-1]});
36         if(x.y+x.c<=m)
37             q.push((nd){x.x,x.y,x.l,x.c+1,sum[x.x+x.l-1][x.y+x.c]-sum[x.x+x.l-1][x.y-1]-sum[x.x-1][x.y+x.c]+sum[x.x-1][x.y-1]});
38         if(x.x+x.l<=n&&x.y+x.c<=m)
39             q.push((nd){x.x,x.y,x.l+1,x.c+1,sum[x.x+x.l][x.y+x.c]-sum[x.x+x.l][x.y-1]-sum[x.x-1][x.y+x.c]+sum[x.x-1][x.y-1]});
40     }
41     return 0;
42 }

20161110

原文地址:https://www.cnblogs.com/YuanZiming/p/6055426.html