zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    CentOS下crond定时任务详细介绍
    js随机从数组中取出几个元素
    js复制内容加版权声明代码
    crond不执行原因分析
    2015年最全的移动WEB前端UI框架
    聊聊前端排序的那些事
    Linux下修改Mysql的用户(root)的密码
    SIPp常用脚本之三:UAC
    SIPp常用脚本之二:UAS
    SIPp常用脚本之一:register注册
  • 原文地址:https://www.cnblogs.com/Narh/p/9755115.html
Copyright © 2011-2022 走看看