您的位置:首页 > 其它

蜡笔

2015-08-29 13:37 246 查看

题目大意

有n(n<=100000)个三元组。现在你需要选k个三元组,使者k个三元组两两差异(差异定义为三元组每一项差值的最大值)最小。

三元组每一项都不超过255。

二分

实际上就是挑选k个三元组使得任意两个三元组中任意项对应元素差值的最大值最小。

最大值最小自然就是二分啦。

不过二分对应的是判定性问题,怎么办呢?

我们可以统计最多能挑选多少个,那么如果这个数量大于等于k,挑选k个自然没有问题。

这就转化为判定性问题了。

观察每一项不超过255。我们二分答案ans后,可以枚举三项的上界,并求出下界,然后统计有多少个三元组每一项都在范围内。

三维前缀和

如何统计呢?

我们可以用三维前缀和以及容斥原理。

每一项可以看作一个约束。那么个数:

符合三个约束的-符合两个约束的+符合一个约束的-都不符合的。

这些都可以用三维前缀和得出。

怎么预处理三维前缀和呢?也要用容斥原理。

设cnt[i][j][k]表示三维前缀和。

cnt[i][j][k]+=(cnt[i-1][j][k]+cnt[i][j-1][k]+cnt[i][j][k-1]-cnt[i-1][j-1][k]-cnt[i-1][j][k-1]-cnt[i][j-1][k-1]+cnt[i-1][j-1][k-1]);


注意

防止越界。

参考程序

#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ME CQF
using namespace std;
int num[4][60],sum[4][60][60],cnt[260][260][260];
int i,j,k,l,r,mid,t,n,m,p,q;
bool czy;
int read(){
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int max(int a,int b){
if (a>b) return a;else return b;
}
int main(){
n=read();m=read();
fo(i,1,n){
j=read();k=read();l=read();
j++;
k++;
l++;
cnt[j][k][l]++;
}
fo(i,1,256)
fo(j,1,256)
fo(k,1,256)
cnt[i][j][k]+=(cnt[i-1][j][k]+cnt[i][j-1][k]+cnt[i][j][k-1]-cnt[i-1][j-1][k]-cnt[i-1][j][k-1]-cnt[i][j-1][k-1]+cnt[i-1][j-1][k-1]);
l=0;
r=255;
while (l<r){
mid=(l+r)/2;
czy=0;
fo(i,1,256){
if (czy) break;
fo(j,1,256){
if (czy) break;
fo(k,1,256){
q=cnt[i][j][k];
q-=cnt[max(i-mid-1,0)][j][k];
q-=cnt[i][max(j-mid-1,0)][k];
q-=cnt[i][j][max(k-mid-1,0)];
q+=cnt[max(i-mid-1,0)][max(j-mid-1,0)][k];
q+=cnt[max(i-mid-1,0)][j][max(k-mid-1,0)];
q+=cnt[i][max(j-mid-1,0)][max(k-mid-1,0)];
q-=cnt[max(i-mid-1,0)][max(j-mid-1,0)][max(k-mid-1,0)];
if (q>=m){
czy=1;
break;
}
}
}
}
if (czy) r=mid;else l=mid+1;
}
printf("%d\n",l);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: