您的位置:首页 > 其它

BZOJ1127: [POI2008]KUP

2017-05-18 15:28 288 查看
题目大意:给一个n*n的非负整数矩阵和一个常数K,要求你找出一个子矩阵使得这个子矩阵的数字和在[K,2K]之间

首先假设有一个格子就在这个范围内,直接输出
否则格子分两种,一种小于K,一种大于2K,其中第二种格子不能选
然后一个比较显然的结论就是,我们若能找出一种不包含第二个格子的子矩形使得其权值和大于等于K,这个子矩形一定有一部分的权值和小于等于2K,因为里面每个元素都不超过K

所以我们可以用一个单调栈搞出所有的极大子矩形,然后若其权值大于2K,就开始砍行和列,直到小于等于2K为止

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2010
using namespace std;
int a
;
bool mp

;
long long pre

;
void YES(int A,int B,int C,int D){printf("%d %d %d %d",A,B,C,D);exit(0);}
int s
,t;
long long cal(int A,int B,int C,int D){return pre[C][D]-pre[A-1][D]-pre[C][B-1]+pre[A-1][B-1];}
int K,n;
void cut(int A,int B,int C,int D)
{
while(cal(A,B,C,D)>2*K)
{
if(A==C) D--;
else if(cal(A+1,B,C,D)>=K) A++;
else C--;
}
YES(B,A,D,C);
}
int main()
{
scanf("%d%d",&K,&n);
int i,j,x,y;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&x);
if(x>=K&&x<=2*K) YES(j,i,j,i);
pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+x;
mp[i][j]=(x<K);
}
for(j=1;j<=n;j++)
{
for(i=1;i<=n;i++)
a[i]=mp[j][i]?a[i]+1:0;
for(i=1;i<=n;i++)
{
while(t&&a[s[t]]>=a[i])
{
if(cal(j-a[s[t]]+1,s[t-1]+1,j,i-1)>=K) cut(j-a[s[t]]+1,s[t-1]+1,j,i-1);
t--;
}
t++;s[t]=i;
}
while(t)
{
if(cal(j-a[s[t]]+1,s[t-1]+1,j,n)>=K) cut(j-a[s[t]]+1,s[t-1]+1,j,n);
t--;
}
}
puts("NIE");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: