说在前面
这 zi 题 ji 真 zhen 厉 cai 害 ji
题目
给出一个 n∗nn∗n 的矩阵 aa 以及一个常数 ,询问是否有一个子矩形满足:K≤子矩形权值和≤2∗KK≤子矩形权值和≤2∗K,如果有,输出这个子矩形的左上角以及右下角坐标,先列后行
范围:n≤2000n≤2000,ai,j≤2∗109ai,j≤2∗109,K≤109K≤109
输入输出格式
输入格式:
第一行两个整数 K,nK,n
接下来是一个 nn 行 列的数字矩阵
输出格式:
如题目中所述,若不存在则输出 NIE
解法
考虑这个问题的一维版本:
首先如果有一个单独的格子满足条件,直接特判就好
然后就是询问是否有一个子串满足条件。显然这个子串不能包含任意一个大于 2K2K 的数字,我们把这样的数字称为「坏点」。假如我们找到了一个不包含坏点的极长子串,如果这个子串的和满足条件就直接输出;不然,因为其中所有数字都小于 KK,我们只需要在两端任意去掉一些数字,一定能获得一个合法的区间
同理推广到二维即可
真厉害
下面是代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , K , K2 , up[2005] ;
bool ban[2005][2005] ;
long long sa[2005][2005] ;
inline bool legal( int x ){ return x >= K && x <= K2 ; }
inline long long sum( int lf , int rg , int up , int dn ){
return sa[dn][rg] - sa[dn][lf-1] - sa[up-1][rg] + sa[up-1][lf-1] ;
}
void cal( int lf , int rg , int up , int dn ){
if( sum( lf , rg , up , dn ) < K ) return ;
while( true ){
if( legal( sum( lf , rg , up , dn ) ) )
printf( "%d %d %d %d" , lf , up , rg , dn ) , exit( 0 ) ;
if( up != dn ){
if( sum( lf , rg , up , up ) <= K ) up ++ ;
else dn -- ;
} else if( lf != rg ) {
if( sum( lf , lf , up , dn ) <= K ) lf ++ ;
else rg -- ;
} else return ;
}
}
int s[2005] , top ;
void solve(){
for( int i = 1 ; i <= N ; i ++ ){
for( int j = 1 ; j <= N ; j ++ )
up[j] = ( ban[i][j] ? 0 : up[j] + 1 ) ;
for( int j = 1 ; j <= N + 1 ; j ++ ){ // N + 1 ---> push_empty
while( top && up[ s[top] ] >= up[j] ){
cal( s[top-1] + 1 , j - 1 , i - up[ s[top] ] + 1 , i ) ;
top -- ;
} s[++top] = j ;
} top = 0 ;
} puts( "NIE" ) ;
}
int main(){
scanf( "%d%d" , &K , &N ) ; K2 = K << 1 ;
for( int i = 1 ; i <= N ; i ++ )
for( int j = 1 ; j <= N ; j ++ ){
scanf( "%lld" , &sa[i][j] ) ;
if( legal( sa[i][j] ) )
printf( "%d %d %d %d" , j , i , j , i ) , exit( 0 ) ;
if( sa[i][j] > K2 ) ban[i][j] = true ;
sa[i][j] += sa[i-1][j] + sa[i][j-1] - sa[i-1][j-1] ;
} solve() ;
}
本文探讨了一种算法,用于解决在一个给定的大规模矩阵中寻找满足特定条件的子矩形的问题。该算法通过排除“坏点”并逐步调整子矩形边界来找到满足条件的子矩形权值和。

527

被折叠的 条评论
为什么被折叠?



