题意
给你
N
个三元组
N,K≤100,000
0≤Ri,Gi,Bi≤255
分析
考试时想到了二分答案,但是一直在想二分后按一个值排序再做,然后卡在那里……还觉得
R,G,B
跟二进制有关系,就走进了死胡同。
正解如下:
仿照二维数组维护前缀和。
数组
f[i][j][k]
,表示
R<i且G<j且B<k
的三元组的个数。这个可以由二维数组类比,容斥得来。然后二分答案,枚举
R,G,B
的下界,得出上界,用
f
<script type="math/tex" id="MathJax-Element-693">f</script>数组和容斥来判断是否满足条件。
计算公式详见代码。
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10,M = 257;
int f[M][M][M];
int n,K;
bool check(int lim) {
for (int i = 1;i <= 256 - lim;i ++) {
for (int j = 1;j <= 256 - lim;j ++) {
for (int k = 1;k <= 256 - lim;k ++) {
int x = i + lim;
int y = j + lim;
int z = k + lim;
int cur = f[x][y][z] - f[i - 1][y][z] - f[x][j - 1][z] - f[x][y][k - 1];
cur += f[i - 1][j - 1][z] + f[i - 1][y][k - 1] + f[x][j - 1][k - 1];
cur -= f[i - 1][j - 1][k - 1];
if (cur >= K)
return true;
}
}
}
return false;
}
int main() {
scanf("%d%d",&n,&K);
for (int i = 1;i <= n;i ++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
x ++,y ++,z ++;
f[x][y][z] ++;
}
for (int i = 1;i <= 256;i ++) {
for (int j = 1;j <= 256;j ++) {
for (int k = 1;k <= 256;k ++) {
f[i][j][k] += f[i - 1][j][k] + f[i][j - 1][k] + f[i][j][k - 1];
f[i][j][k] -= f[i - 1][j - 1][k] + f[i - 1][j][k - 1] + f[i][j - 1][k - 1];
f[i][j][k] += f[i - 1][j - 1][k - 1];
}
}
}
int ans = 0,r = 255;
while (ans < r) {
int mid = (ans + r) >> 1;
if (check(mid)) r = mid;
else ans = mid + 1;
}
printf("%d",ans);
}