BZOJ 1127: [POI2008]KUP|单调队列|思路题

来源:互联网 发布:公安民警网络答题 编辑:程序博客网 时间:2024/06/05 10:04

思路神题
考虑子矩阵为1*n的情况 如果有一个[k,2*k]的点直接输出
否则这些区间中满足条件的一定是所有数都< k他们的和>=k
考虑二维的情况也是这样,子矩阵中必须所有的数都< k
找出一个极大的不含>2*k的数的子矩阵
如果< k,直接忽略,否则肯定存在一个子矩阵满足条件
如果他们的和>=k并且<=2*k直接输出
如果他们的和>2*k,上下左右随便砍几次就能满足条件
找出极大子矩阵要用单调队列
似乎我并没有用,乱搞了个比较奇怪的东西,复杂度也是线性的

#include<set>#include<map>#include<ctime>#include<queue>#include<cmath>#include<cstdio>#include<vector>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>#define T 2002#define MX 1e9#define pa pair<int,int>using namespace std;int sc(){    int i=0,f=1; char c=getchar();    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}    while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();    return i*f;}int n,k,a[T][T],h[T],l[T],r[T];long long sum[T][T];long long SUM(int x1,int y1,int x2,int y2){    return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];}void print(int x1,int y1,int x2,int y2){    while(SUM(x1,y1,x2,y2)>2*k)    {        if(x1==x2)y1++;        else        {            if(SUM(x1+1,y1,x2,y2)>=k) x1++;            else x2--;        }    }    printf("%d %d %d %d\n",y1,x1,y2,x2);    exit(0);}void cal(int x){    for(int i=1;i<=n;i++)l[i]=r[i]=i;    for(int i=1;i<=n;i++)if(h[i])while(h[l[i]-1]>=h[i])l[i]=l[l[i]-1];    for(int i=n;i>=1;i--)if(h[i])while(h[r[i]+1]>=h[i])r[i]=r[r[i]+1];    for(int i=1;i<=n;i++)    {        if(h[i])        {            long long temp=SUM(x-h[i]+1,l[i],x,r[i]);            if(temp>=k) print(x-h[i]+1,l[i],x,r[i]);        }    }}   int main(){    k=sc(),n=sc();    for(int i=1;i<=n;i++)    {        for(int j=1;j<=n;j++)        {            a[i][j]=sc();            if(a[i][j]>=k&&a[i][j]<=2*k)            {                printf("%d %d %d %d",j,i,j,i);                return 0;            }            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++)        {            h[j]=a[i][j]>2*k?0:h[j]+1;        }        cal(i);    }    puts("NIE");    return 0;}
0 0