zoukankan      html  css  js  c++  java
  • 【BZOJ-1127】KUP 悬线法 + 贪心

    1127: [POI2008]KUP

    Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge
    Submit: 317  Solved: 111
    [Submit][Status][Discuss]

    Description

    给一个n*n的地图,每个格子有一个价格,找一个矩形区域,使其价格总和位于[k,2k]

    Input

    输入k n(n<2000)和一个n*n的地图

    Output

    输出矩形的左上和右下的列-行坐标或NIE

    Sample Input

    inputdata1
    4 3
    1 1 1
    1 9 1
    1 1 1
    inputdata2
    8 4
    1 2 1 3
    25 1 2 1
    4 20 3 3
    3 30 12 2

    Sample Output

    outputdata1
    NIE
    outputdata2
    2 1 4 2

    HINT

    1<=k<=10^9 每个价格都是不大于2*10^9的非负整数

    Source

    感谢vfleaking提供SPJ

    Solution

    这个题需要思路....

    首先假设有一个一维的区间$[l,r]$,那么假设这个区间中满足$forall x,x<K$,那么且这个区间的和$>=K$,那么答案肯定存在在这个区间中。

    证明:

    因为这个区间中满足$forall x,x<K$,所以区间和每加上一个数,区间和的变化量一定是$<K$的;

    所以,并不会存在一个数使得一个子区间(连续的)和加上他得到的新区间和直接从$(-infty,K]$跳过$[K,2*K]$变成$[2*K,+infty)$.

    所以,只要从这个一维的区间的左/右端开始一一删除,就可以得到满足条件的区间。

    但是这里的$N*N$的矩阵,所以要利用这个结论就必须扩展到多维区间块上面,但是这个结论是可以拓展的。

    这样就是一个子矩阵满足$forall x,x<K$,且子矩阵和$>=K$,那么这个子矩阵中存在答案。

    证明类比上面的证明,这里分类讨论一下,可以利用上面的方法,先一行一行的删除,删成满足条件的,或者只剩一行,转成上述,再一个一个删.

    然后就是找出这些需要搞得子矩形的方法了,把$x>2*K$的点认为是障碍,做一遍悬线法,就可以得到所有的极大子矩形,然后一一判断。

    当然一开始读入的时候,如果存在一个$1*1$的位置$x$直接满足$x in [K,2*K]$那么可以直接输出。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define LL long long
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    int K,N,l[2010][2010],r[2010][2010],h[2010][2010];
    LL sum[2010][2010],a[2010][2010];
    inline LL Sum(int x1,int y1,int x2,int y2) {return sum[x2][y2]+sum[x1-1][y1-1]-sum[x2][y1-1]-sum[x1-1][y2];}
    inline void Cut(int x1,int y1,int x2,int y2)
    {
        while (Sum(x1,y1,x2,y2)>2*K)
            {
                if (x1==x2) {y2--; continue;}
                if (Sum(x1,y1,x2-1,y2)>=K) {x2--; continue;}
                if (Sum(x1+1,y1,x2,y2)>=K) {x1++; continue;}
            }
        printf("%d %d %d %d
    ",y1,x1,y2,x2);
        exit(0);
    }
    int main()
    {
        K=read(),N=read();
        for (int i=1; i<=N; i++)
            for (int j=1; j<=N; j++)
                a[i][j]=read(),sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
        for (int i=1; i<=N; i++)
            for (int j=1; j<=N; j++)
                if (a[i][j]>=K && a[i][j]<=2*K) {printf("%d %d %d %d
    ",j,i,j,i); return 0;}
        for (int i=1; i<=N; i++)
            {
                for (int j=1,x=0; j<=N; j++)
                    if (a[i][j]<=2*K) l[i][j]=x; else l[i][j]=0,x=j;
                for (int j=N,x=N+1; j>=1; j--)
                    if (a[i][j]<=2*K) r[i][j]=x; else r[i][j]=N+1,x=j;
            }
        for (int i=1; i<=N+1; i++) r[0][i]=N+1;
        for (int i=1; i<=N; i++)
            for (int j=1; j<=N; j++)
                if (a[i][j]<=2*K)
                    h[i][j]=h[i-1][j]+1,
                    l[i][j]=max(l[i][j]+1,l[i-1][j]),
                    r[i][j]=min(r[i][j]-1,r[i-1][j]);
        
    //    puts("==========================");               
    //    for (int i=1; i<=N; i++,puts(""))
    //        for (int j=1; j<=N; j++)
    //            printf("%d  ",h[i][j]);
    //    puts("==========================");
    //    for (int i=1; i<=N; i++,puts(""))
    //        for (int j=1; j<=N; j++)
    //            printf("%d  ",l[i][j]);
    //    puts("==========================");
    //    for (int i=1; i<=N; i++,puts(""))
    //        for (int j=1; j<=N; j++)
    //            printf("%d  ",r[i][j]);
    //    puts("==========================");
        
        for (int i=1; i<=N; i++)
            for (int j=1; j<=N; j++)
                if (a[i][j]<=2*K){
    //                printf("%d    %d    %d    %d
    ",i-h[i][j]+1,l[i][j],i,r[i][j]);
                    if (Sum(i-h[i][j]+1,l[i][j],i,r[i][j])>=K) Cut(i-h[i][j]+1,l[i][j],i,r[i][j]);
                }
        puts("NIE");
        return 0;
    }
    /*
    2 3
    3  25 7
    6  1  2
    16 11 20
    */
  • 相关阅读:
    如何给wordpress外部链接自动添加nofollow
    wordpress如何批量关闭旧日志留言功能
    如何一次把所有wordpress插件都禁用了
    sql批量获取wordpress所有留言者的邮件地址
    wordpress数据库优化-关闭日志修订
    wordpress数据库优化wp_posts表 OPTIMIZE
    sql批量删除wordpress所有日志修订revision
    sql删除wordpress没用的postmeta记录
    wordpress如何删除没有文章的tags标签
    批量删除wordpress垃圾评论留言
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5997325.html
Copyright © 2011-2022 走看看