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的非负整数
题解
有点意思
1*1的直接判了
单考虑1*n的矩阵,如果有至少一个区间满足和>K且每个数都<=K那么一定合法
因为每个数都<=K,所以前缀和不会从<K直接蹦到>2*K
扩展到2维,同样成立
先悬线法求出每个数都<=K的和最大矩阵
考虑怎么从这里构造,选出最上面一行和最下面一行
设当前总和是S
显然至少有一行的和是<S/2的
由于原来的和>2*K
所以删去较小的那行后不会蹦到<K
那直接做就行了…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;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 stack[20];
inline void write(int x)
{
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
LL prefix[2005][2005];
int n,K,a[2005][2005];
LL S(int u1,int v1,int u2,int v2){return prefix[u2][v2]-prefix[u1-1][v2]-prefix[u2][v1-1]+prefix[u1-1][v1-1];}
int L[2005][2005],R[2005][2005],up[2005][2005];
int ll[2005][2005],rr[2005][2005];
bool check(int nn1,int nn2)
{
int u1=nn1-up[nn1][nn2]+1,v1=nn2-ll[nn1][nn2]+1;
int u2=nn1,v2=nn2+rr[nn1][nn2]-1;
if(S(u1,v1,u2,v2)<K)return false;
while(S(u1,v1,u2,v2)>2*K)
{
if(u1<u2)
{
LL s1=S(u1,v1,u1,v2),s2=S(u2,v1,u2,v2);
if(s1<s2)u1++;
else u2--;
}
else
{
LL s1=S(u1,v1,u1,v1),s2=S(u2,v2,u2,v2);
if(s1<s2)v1++;
else v2--;
}
}
pr1(v1);pr1(u1);pr1(v2);pr2(u2);
return true;
}
int main()
{
// freopen("23.in","r",stdin);
// freopen("a.out","w",stdout);
K=read();n=read();
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
{
a[i][j]=prefix[i][j]=read();
if(a[i][j]>=K&&a[i][j]<=2*K)
{
pr1(j);pr1(i);pr1(j);pr2(i);
return 0;
}
}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)prefix[i][j]+=prefix[i][j-1];
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)prefix[i][j]+=prefix[i-1][j];
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(a[i][j]<K)L[i][j]=L[i][j-1]+1;
for(int i=1;i<=n;i++)for(int j=n;j>=1;j--)if(a[i][j]<K)R[i][j]=R[i][j+1]+1;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
if(a[i][j]<K)
{
if(i==1 ||a[i-1][j]>2*K)ll[i][j]=L[i][j],rr[i][j]=R[i][j],up[i][j]=1;
else
{
ll[i][j]=min(ll[i-1][j],L[i][j]);rr[i][j]=min(rr[i-1][j],R[i][j]);
up[i][j]=up[i-1][j]+1;
}
}
LL mx=0;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)mx=max(mx,S(i-up[i][j]+1,j-ll[i][j]+1,i,j+rr[i][j]-1));
bool tf=false;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(S(i-up[i][j]+1,j-ll[i][j]+1,i,j+rr[i][j]-1)==mx)
{
tf|=check(i,j);
if(tf)break;
}
if(!tf)puts("NIE");
return 0;
}