趣题[1]
来源
http://www.csie.ntnu.edu.tw/~u91029/Sequence3.html
UVA - 12192
介绍
引入
(n*m)的矩阵,每行从左到右递增,每列从上到下递增,在矩阵中找数(x)出现过的位置。
具体做法可以在这个链接ctrl+F[Search in Sorted Matrix: Saddleback Search],复杂度(O(n+m))
想法
现在我们知道了,从这样的矩阵的右上角走下来可以把矩阵分成两个部分,左上部分小于(x),右下部分大等于(x),这样的想法有什么用呢?
小小的实战!
UVA - 12192
题目要求在(n*m)的矩阵中找一个最大的方阵,使得方阵中所有的元素都在区间([L, R])中。(1<=n,m<=500) 询问(10000)次。
做法:把矩阵分成两个部分,左上部分小于(L),右下部分大等于(L),然后二分方阵的边长,check时判断方针的右下角是不是小等于(R)就可以啦。复杂度(O(q*(n+m)*logn))
代码:
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define sz(x) (int)x.size()
#define de(x) cout<< #x<<" = "<<x<<endl
#define dd(x) cout<< #x<<" = "<<x<<" "
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
//------
const int N=555;
int n,m,l,r;
int a[N][N];
int gao(int x,int y) {
if(a[x][y]>r||a[x][y]<l) return 0;
int lo=1,hi=min(n-x+1, m-y+1);
int ans=0;
while(lo<=hi) {
int mid=(lo+hi)>>1;
if(a[x+mid-1][y+mid-1]<=r) {
ans=mid;
lo=mid+1;
} else {
hi=mid-1;
}
}
return ans;
}
int solve() {
int ans=0;
int x=1,y=m;
ans=max(ans,gao(x,y));
while(1) {
if(y==1||a[x][y-1]<l) {
if(x<n) ++x;
else break;
} else {
--y;
}
ans=max(ans,gao(x,y));
}
return ans;
}
int main() {
while(~scanf("%d%d",&n,&m)) {
if(n==0&&m==0) break;
///read
rep(i,1,n+1) {
rep(j,1,m+1) {
scanf("%d",&a[i][j]);
}
}
///solve
int q;scanf("%d",&q);
while(q--) {
scanf("%d%d",&l,&r);
printf("%d
",solve());
}
puts("-");
}
return 0;
}