ζ

POJ3685-Matrix

    题解

题目大意:给出一个n*n的矩阵a,且

1
a[i][j] = i * i + 100000 * i + j * j - 100000 * j + i * j

求矩阵中第m小的元素的值。

二分枚举可能的第m小元素值x,判断比它小的元素是否少于m个,如果是,则第m小的元素值小于等于x,否则第m小的元素值大于x。

怎么判断比x小的元素是否少于m个?注意到:当j一定时,a[i][j]的值随i的增大而增大。因此对于每一个j,二分查找小于x的最大a[i][j]。若这个满足条件的最大a[i][j]a[t][j],那么a[][j]中就一共有t个比x小的元素。对每一个j找一遍这个t,加起来,就是整个矩阵中比x小的元素个数了

于是可以写出代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
using namespace std;
long long n, m;
// C:判断矩阵中小于x的元素数量是否少于m,如果不少于则x大了,返回false。否则就是x<=最终答案,返回true
bool C(long long x)
{
long long sum = 0, j;
for (j = 1; j <= n; j++)
{
// j相同时,随着i增大,a[i][j]递增。下面找出矩阵各第j列中满足a[i][j]<x最大的i
long long l = 0, r = 1e5, md;
while (r - l > 1)
{
md = l + ((r - l) >> 1);
if (md * md + 100000 * md + j * j - 100000 * j + md * j < x)
l = md;
else
r = md;
}
sum += l;
}
return sum < m;
}
int main()
{
int _;
scanf("%d", &_);
while (_--)
{
scanf("%lld%lld", &n, &m);
long long l = -1e10, r = 1e10, md;
while (r - l > 1)
{
md = l + ((r - l) >> 1);
if (C(md))
l = md;
else
r = md;
}
printf("%lld\n", l);
}
return 0;
}

但这个代码连样例都过不了。因为函数C中的二分可能会使l找到数组右边界的地方导致错误。所以应该这么写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
using namespace std;
long long n, m;
// C:判断矩阵中小于x的元素数量是否少于m,如果不少于则x大了,答案小于x;少于则答案大于等于x
bool C(long long x)
{
long long sum = 0, j;
for (j = 1; j <= n; j++)
{
// j相同时,随着i增大,a[i][j]递增。下面找出矩阵各第j列中满足a[i][j]<x最大的i
long long l = 0, r = 1e5, md;
while (r - l > 1)
{
md = l + ((r - l) >> 1);
if (md <= n && md * md + 100000 * md + j * j - 100000 * j + md * j < x)
l = md;
else
r = md;
}
sum += l;
}
return sum < m;
}
int main()
{
int _;
scanf("%d", &_);
while (_--)
{
scanf("%lld%lld", &n, &m);
long long l = -1e10, r = 1e10, md;
while (r - l > 1)
{
md = l + ((r - l) >> 1);
if (C(md))
l = md;
else
r = md;
}
printf("%lld\n", l);
}
return 0;
}
页阅读量:  ・  站访问量:  ・  站访客数: