POJ - 3685 Matrix (二分搜索:查找第k大的值)

来源:互联网 发布:江门数控冲床编程招聘 编辑:程序博客网 时间:2024/05/13 12:39

http://poj.org/problem?id=3685

题意:

定义一个N*N矩阵:Aij =  i2 + 100000 × i + j2 - 100000 × j + i × j。

求第M大的值。

N(1 ≤ N ≤ 50,000) and M(1 ≤ M ≤ N × N).

——————————————————————————

跟这题有点类似: POJ - 3685 Median(二分搜索,查找第K大的值)

这个矩阵有个规律:每列单调递增。可以根据这个分别对每一列进行二分搜索,求出比x小的个数,得出排在第几位。x的枚举也是通过一个二分搜索得出。

总的时间复杂度为:O(log(MAX_Aij)*N*log(N))。

这里的MAX_Aij懒得算了,就直接用long long的上下限吧……= =。

这题因为二分搜索的上下界出了许多问题,反复调试了很久,感觉while(r - l > 1)这种方法确实不太好。


#include <iostream>#include <cstdio>#include <algorithm>using namespace std;const int MAX_N = 1e5;long long  N, M;inline long long getnum(long long  i,long long j){return i*i + 100000 * i + j*j - 100000 * j + i * j;}bool C(long long x){long long cnt = 0;for(int j = 1; j <= N; j++){if(x > getnum(N, j))cnt += N;else{int l = 0, r = N;while(r - l > 1){int mid = (l+r)/2;if(getnum(mid, j) >= x)r = mid;elsel = mid;}//cnt += N - r + 1;cnt += r - 1;}}//return cnt > N*N-M;return cnt >= M;//左}void solve(){//#define DEBUG#ifdef DEBUGfor(int i = 1; i <= N; i++)for(int j = 1; j <= N; j++)printf(j == N ? "%10lld\n": "%10lld ", getnum(i, j));#endifif(N == 1){printf("3\n");return ;}long long l = -0x3fffffffffffffff, r = 0x3fffffffffffffff;while(r - l > 1){long long mid = (l+r)/2;if(C(mid))r = mid;elsel = mid;}printf("%lld\n", l);}int main(){//freopen("in.txt", "r", stdin);//freopen("out.txt", "w", stdout);int T;scanf("%d", &T);while(T--){scanf("%lld%lld", &N, &M);solve();}return 0;}


0 0