原来看过然后没做,结果板板把这道题改了改考掉了,血亏=。=
首先看看有没有符合条件的点。如果没有开始寻找解,先把所有的大于$2*k$的点设为坏点,然后求最大子矩形,只要一个最大子矩形的权值和超过$2*k$则它的一个子矩形一定可以成为解。因为这时所有点都小于$k$,这个最大子矩形既然权值和超过$2*k$那么一定是有一部分落在所求的区间中,然后逐行/列枚举切一下是一定有解的。
注意最大子矩形的边界(为什么你们的最大子矩形都要做两遍啊=。=)

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=2005; 6 struct a 7 { 8 int xx,yy,zz; 9 }stk[N],str; 10 long long fsum[N][N]; 11 int mapp[N][N],dp[N][N]; 12 long long n,k,rd,top,ans; 13 void gun(){exit(0);} 14 long long getsum(int x1,int y1,int x2,int y2) 15 { 16 return fsum[x2][y2]-fsum[x1-1][y2]-fsum[x2][y1-1]+fsum[x1-1][y1-1]; 17 } 18 void check(int x1,int y1,int x2,int y2) 19 { 20 if(x1>x2||y1>y2) return ; 21 long long sum=getsum(x1,y1,x2,y2); if(sum<k) return ; 22 if(sum>=k&&sum<=2*k) printf("%d %d %d %d",y1,x1,y2,x2),gun(); 23 for(int i=x1+1;i<=x2;i++) 24 { 25 long long t1=getsum(i,y1,x2,y2),t2=sum-t1; 26 if(t1>=k&&t1<=2*k) printf("%d %d %d %d",y1,i,y2,x2),gun(); 27 else if(t2>=k&&t2<=2*k) printf("%d %d %d %d",y1,x1,y2,i),gun(); 28 } 29 return ; 30 } 31 int main () 32 { 33 scanf("%lld%lld",&k,&n); 34 for(int i=1;i<=n;i++) 35 for(int j=1;j<=n;j++) 36 { 37 scanf("%lld",&rd),mapp[i][j]=(rd<=2*k),fsum[i][j]=rd; 38 if(rd<=2*k&&rd>=k) printf("%d %d %d %d",j,i,j,i),gun(); 39 } 40 for(int i=1;i<=n;i++) 41 for(int j=1;j<=n;j++) 42 { 43 fsum[i][j]+=fsum[i-1][j]+fsum[i][j-1]-fsum[i-1][j-1]; 44 if(mapp[i][j]) dp[i][j]=dp[i-1][j]+1; 45 } 46 for(int i=1;i<=n;i++) 47 for(int j=1;j<=n+1;j++) 48 { 49 str.xx=j,str.yy=dp[i][j],str.zz=i; 50 if(!top||stk[top].yy<str.yy) stk[++top]=str; 51 else 52 { 53 int tmp=j; 54 while(top&&stk[top].yy>=str.yy) 55 check(stk[top].zz-stk[top].yy+1,stk[top].xx,stk[top].zz,j-1),tmp=stk[top--].xx; 56 str.xx=tmp,stk[++top]=str; 57 } 58 } 59 printf("NIE"); 60 return 0; 61 }