题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1127
首先,把权值 > 2*k 的点作为“坏点”,然后在图中用悬线法找权值最大的子矩形;
如果权值最大的子矩形的权值 < k ,那么无解;
否则,针对这个子矩形,一列一列地删掉元素,某一时刻权值一定会变成 k~2*k 或 < k;
如果变成 k~2*k ,直接输出即可;
如果变成 < k,那么刚才删掉的那一列的权值 > k;
针对那一列,如果权值和就是 k~2*k,输出那一列;
否则,针对这一列,一个一个删除元素,因为此时元素的权值都是 < k 的,所以总会有某一时刻删成 k~2*k,即为答案;
注意输出的坐标是 列-行 !!!
还要注意一个一个删除列上的元素时,符合答案后的坐标是 i+1 !!!
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=2005; int n,k,v[xn][xn],l[xn][xn],r[xn][xn],s[xn][xn]; ll sum[xn][xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } ll get(int a,int b,int c,int d){return sum[c][d]-sum[a-1][d]-sum[c][b-1]+sum[a-1][b-1];} int main() { k=rd(); n=rd(); int a=0,b=0,c,d; for(int i=1;i<=n;i++) { int tmp=1; for(int j=1;j<=n;j++) { v[i][j]=rd(); sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+v[i][j]; if(v[i][j]>=k&&v[i][j]<=2*k)a=i,b=j; if(v[i][j]>2*k){tmp=j+1; continue;} s[i][j]=s[i-1][j]+1; if(v[i-1][j]>2*k||i==1)l[i][j]=tmp; else l[i][j]=max(tmp,l[i-1][j]); } tmp=n; for(int j=n;j;j--) { if(v[i][j]>2*k){tmp=j-1; continue;} if(v[i-1][j]>2*k||i==1)r[i][j]=tmp; else r[i][j]=min(tmp,r[i-1][j]); } } if(a){printf("%d %d %d %d\n",b,a,b,a); return 0;} ll mxs=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(v[i][j]>2*k)continue; int ta=i-s[i][j]+1,tb=l[i][j],tc=i,td=r[i][j]; ll ts=get(ta,tb,tc,td); if(ts<k)continue; if(ts>mxs)mxs=ts,a=ta,b=tb,c=tc,d=td; } if(!mxs){printf("NIE\n"); return 0;} if(mxs>=k&&mxs<=2*k){printf("%d %d %d %d\n",b,a,d,c); return 0;} for(int j=b;j<=d;j++) { mxs-=get(a,j,c,j); if(mxs>=k&&mxs<=2*k){printf("%d %d %d %d\n",j+1,a,d,c); return 0;} else if(mxs<k) { ll ts=get(a,j,c,j); if(ts>=k&&ts<=2*k){printf("%d %d %d %d\n",j,a,j,c); return 0;} for(int i=a;i<=c;i++) { ts-=v[i][j]; if(ts>=k&&ts<=2*k){printf("%d %d %d %d\n",j,i+1,j,c); return 0;}//i+1!!! } } } return 0; }