bzoj 1127 [POI2008]KUP——思路(悬线法)

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

大于2*K的视为不能选的“坏点”。有单个格子满足的就直接输出。

剩下的都是<K的格子,求面积大于等于K的一个矩形;若还<=2*K就直接输出,否则一列一列删;

删去一列后若仍>=2*K,继续;若>=K&&<=2*K,就输出;若<K,则删去的那一列满足>=K,在那列上一格一格删,因为格子<K,所以不能从>2*K跳到<K,一定有解了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=2005;
int n,K,D,a[N][N],l[N][N],r[N][N],u[N][N],p0,p1;
ll s[N][N];
bool b[N][N],flag;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
ll calc(int h1,int l1,int h2,int l2)
{
  return s[h2][l2]-s[h2][l1-1]-s[h1-1][l2]+s[h1-1][l1-1];
}
void solve2(int h1,int h2,int j)
{
  int sm=calc(h1,j,h2,j);
  if(sm>=K&&sm<=D){printf("%d %d %d %d
",j,h1,j,h2);return;}
  for(int i=h2;i>=h1;i--)
    {
      sm-=a[i][j];
      if(sm>=K&&sm<=D){printf("%d %d %d %d
",j,h1,j,i-1);return;}
    }
}
void solve(int h1,int l1,int h2,int l2)
{
  ll sm=calc(h1,l1,h2,l2);
  if(sm<K)return;
  if(sm>=K&&sm<=D){printf("%d %d %d %d
",l1,h1,l2,h2);flag=1;return;}
  for(int i=l2;i>=l1;i--)
    {
      sm=calc(h1,l1,h2,i-1);
      if(sm>=K&&sm<=D)
    {
      printf("%d %d %d %d
",l1,h1,i-1,h2);
      flag=1;return;
    }
      if(sm<K)
    {
      solve2(h1,h2,i);flag=1;return;
    }
    }
}
int main()
{
  K=rdn(); n=rdn(); D=(K<<1);
  for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
      {
    a[i][j]=rdn(); if(a[i][j]>D)b[i][j]=1;
    if(a[i][j]>=K&&a[i][j]<=D)p0=j,p1=i;
    s[i][j]=s[i][j-1]+a[i][j];
      }
  if(p0){printf("%d %d %d %d
",p0,p1,p0,p1);return 0;}
  for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)s[i][j]+=s[i-1][j];

  for(int i=1,k;i<=n;i++)
    for(int j=1,k=1;j<=n;j++)
      {
    if(!b[i-1][j]) u[i][j]=u[i-1][j]+1;
    else u[i][j]=1;
    if(!b[i][j])l[i][j]=max(k,l[i-1][j]);
    else k=j+1;
      }
  for(int j=1;j<=n;j++)r[0][j]=n;//!
  for(int i=1,k;i<=n;i++)
    for(int j=n,k=n;j>=1;j--)
      {
    if(!b[i][j])r[i][j]=min(k,r[i-1][j]);
    else k=j-1,r[i][j]=n;//for don't influence i+1,j
    if(!b[i][j])solve(i-u[i][j]+1,l[i][j],i,r[i][j]);
    if(flag)return 0;
      }
  puts("NIE");
  return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/9755115.html