bzoj 1127 KUP —— 最大子矩形+答案构造

Posted zinn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1127 KUP —— 最大子矩形+答案构造相关的知识,希望对你有一定的参考价值。

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1127

首先,把权值 > 2*k 的点作为“坏点”,然后在图中用悬线法找权值最大的子矩形;

如果权值最大的子矩形的权值 < k ,那么无解;

否则,针对这个子矩形,一列一列地删掉元素,某一时刻权值一定会变成 k~2*k 或 < k;

如果变成 k~2*k ,直接输出即可;

如果变成 < k,那么刚才删掉的那一列的权值 > k;

针对那一列,如果权值和就是 k~2*k,输出那一列;

否则,针对这一列,一个一个删除元素,因为此时元素的权值都是 < k 的,所以总会有某一时刻删成 k~2*k,即为答案;

注意输出的坐标是 列-行 !!!

还要注意一个一个删除列上的元素时,符合答案后的坐标是 i+1 !!!

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=2005;
int n,k,v[xn][xn],l[xn][xn],r[xn][xn],s[xn][xn];
ll sum[xn][xn];
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<0||ch>9){if(ch==-)f=0; ch=getchar();}
  while(ch>=0&&ch<=9)ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar();
  return f?ret:-ret;
}
ll get(int a,int b,int c,int d){return sum[c][d]-sum[a-1][d]-sum[c][b-1]+sum[a-1][b-1];}
int main()
{
  k=rd(); n=rd(); int a=0,b=0,c,d;
  for(int i=1;i<=n;i++)
    {
      int tmp=1;
      for(int j=1;j<=n;j++)
        {
          v[i][j]=rd();
          sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+v[i][j];
          if(v[i][j]>=k&&v[i][j]<=2*k)a=i,b=j;
          if(v[i][j]>2*k){tmp=j+1; continue;}
          s[i][j]=s[i-1][j]+1;
          if(v[i-1][j]>2*k||i==1)l[i][j]=tmp;
          else l[i][j]=max(tmp,l[i-1][j]);
        }
      tmp=n;
      for(int j=n;j;j--)
        {
          if(v[i][j]>2*k){tmp=j-1; continue;}
          if(v[i-1][j]>2*k||i==1)r[i][j]=tmp;
          else r[i][j]=min(tmp,r[i-1][j]);
        }
    }
  if(a){printf("%d %d %d %d
",b,a,b,a); return 0;}
  ll mxs=0;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
      {
        if(v[i][j]>2*k)continue;
        int ta=i-s[i][j]+1,tb=l[i][j],tc=i,td=r[i][j];
        ll ts=get(ta,tb,tc,td);
        if(ts<k)continue;
        if(ts>mxs)mxs=ts,a=ta,b=tb,c=tc,d=td;
      }
  if(!mxs){printf("NIE
"); return 0;}
  if(mxs>=k&&mxs<=2*k){printf("%d %d %d %d
",b,a,d,c); return 0;}
  for(int j=b;j<=d;j++)
    {
      mxs-=get(a,j,c,j);
      if(mxs>=k&&mxs<=2*k){printf("%d %d %d %d
",j+1,a,d,c); return 0;}
      else if(mxs<k)
        {
          ll ts=get(a,j,c,j);
          if(ts>=k&&ts<=2*k){printf("%d %d %d %d
",j,a,j,c); return 0;}
          for(int i=a;i<=c;i++)
            {
              ts-=v[i][j];
              if(ts>=k&&ts<=2*k){printf("%d %d %d %d
",j,i+1,j,c); return 0;}//i+1!!!
            }
        }
    }
  return 0;
}

 

以上是关于bzoj 1127 KUP —— 最大子矩形+答案构造的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1127[POI2008]KUP 悬线法

1127: [POI2008]KUP

[bzoj1084]最大子矩阵

bzoj3039玉蟾宫 悬线法

[bzoj1177]Oil

bzoj 5085: 最大——结论题qwq