原题链接:https://ac.nowcoder.com/acm/contest/3570/L;
分析:一看题目,求矩形中所有值的和,差不多就是二维前缀和。但是,如果简单的用二维前缀和遍历每一个点,每一个边长,超时!
接着,我们看,这个边长是可以二分的!
具备二分的条件:区间具有单调性!边长越大,求出的矩阵所有值的和越大!
于是,我们就二分边长!
这样,将遍历边长的复杂度O(n)降低为O(log n)!
总复杂度:O(n * n * log n)
code:
#include<iostream>
using namespace std;
const int N=2010;
long long a[N][N],n,sum;
int ans=1e9;
int main(){
cin>>n>>sum;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&a[i][j]); //输入过多,用scanf
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1]; //求二位前缀
}
}
//对每个位置,二分矩形(正方形)的边长
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int l=0,r=min(n-i,n-j); //以该位置为左上角,增加的边长长度
while(l<r)
{
int mid=l+r>>1;
if(a[i+mid][j+mid]-a[i-1][j+mid]-a[i+mid][j-1]+a[i-1][j-1]>=sum) r=mid;
//二位前缀,求以(i,j)为左上角,以(i+mid,l+mid)为右下角的矩形中所有值的和,大于等于目标值,说明边长偏大
else l=mid+1;
}
if(a[i+l][j+l]-a[i-1][j+l]-a[i+l][j-1]+a[i-1][j-1]>=sum){ //检查是否找到
ans=min(ans,l);
}
}
}
if(ans!=1e9) cout<<ans+1;
else cout<<"I'm a Gold Chef!";
return 0;
}
如果对 二维前缀和
或 二分
不太熟的话,可以看我的两个博客(前缀和&差分,二分查找&二分答案)专门讲这两个知识点!
如果有问题的话,欢迎留言评论!