[POI2008]KUP-Plot purchase(单调队列)

题意

给定k,n,和n*n的矩阵,求一个子矩形满足权值和在[k,2k]之间

 ,

题解

这里用到了极大化矩阵的思想。推荐论文《浅谈用极大化思想解决最大子矩阵问题》Orz

如果有一个元素在[k,2k]之间。直接输出就好。

否则。把所有大于2k的元素作为障碍点。

求每一个最大化矩阵。(用单调队列)

如果这个矩阵权值和大于等于k

那么这个矩阵一定有一个子矩阵满足条件。这个结论可以证明。

假设这个矩阵权值和小于等于2k则直接输出这个矩阵。

否则这个矩阵权值和一定大于2k

假设这个矩阵去掉第一行后权值和大于k,则去掉第一行后的矩阵继续操作。

假设权值和小于等于k则矩阵的第一行权值和一定大于k,所以一个一个去除这一行的元素判断即可。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm> 
 6 using namespace std;
 7 const long long N=2010;
 8 long long n,k,a[N][N],book[N][N],sum[N][N],sum1[N][N],top,stack[N],r[N],l[N];
 9 void work(long long x1,long long y1,long long x2,long long y2){
10     if(sum1[x2][y2]-sum1[x2][y1-1]-sum1[x1-1][y2]+sum[x1-1][y1-1]<=2*k){
11         cout<<y1<<" "<<x1<<" "<<y2<<" "<<x2;
12         return ;
13     }
14     while(sum1[x2-1][y2]-sum1[x2-1][y1-1]-sum1[x1-1][y2]+sum1[x1-1][y1-1]>=k){
15         x2--;
16     }
17     while(sum1[x2][y2]-sum1[x2][y1-1]-sum1[x2-1][y2]+sum1[x2-1][y1-1]>2*k)y1++;
18     cout<<y1<<" "<<x2<<" "<<y2<<" "<<x2;
19 }
20 int main(){
21     scanf("%lld%lld",&k,&n);
22     for(long long i=1;i<=n;i++)
23         for(long long j=1;j<=n;j++){
24             scanf("%lld",&a[i][j]);
25             if(a[i][j]>=k&&a[i][j]<=2*k){
26                 cout<<j<<" "<<i<<" "<<j<<" "<<i;
27                 return 0;
28             }
29             if(a[i][j]>2*k)book[i][j]=1;
30             if(book[i][j])sum[i][j]=0;
31             else sum[i][j]=sum[i-1][j]+1;
32             sum1[i][j]=sum1[i-1][j]+sum1[i][j-1]-sum1[i-1][j-1]+a[i][j];
33         }
34     for(long long i=1;i<=n;i++){
35         top=0;
36         for(long long j=1;j<=n;j++){
37             while(sum[i][j]<sum[i][stack[top]]){
38                 r[stack[top]]=j-1;
39                 top--;
40             }
41             stack[++top]=j;
42         }
43         while(top){
44             r[stack[top--]]=n;
45         }
46         top=0;
47         for(long long j=n;j>=1;j--){
48             while(sum[i][j]<sum[i][stack[top]]){
49                 l[stack[top]]=j+1;
50                 top--;
51             }
52             stack[++top]=j;
53         }
54         while(top){
55             l[stack[top--]]=1;
56         }
57         for(long long j=1;j<=n;j++){
58             if(sum1[i][r[j]]-sum1[i][l[j]-1]-sum1[i-sum[i][j]][r[j]]+sum1[i-sum[i][j]][l[j]-1]>=k){
59                 work(i-sum[i][j]+1,l[j],i,r[j]);
60                 return 0;
61             }
62         }
63     }
64     printf("NIE");
65     return 0;
66 }

 

posted @ 2018-08-08 15:34  Xu-daxia  阅读(275)  评论(0编辑  收藏  举报