1. 程式人生 > >[bzoj1127][懸線法]KUP

[bzoj1127][懸線法]KUP

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; }