Codeforces 733D 立方体(想法题)

题目:http://codeforces.com/contest/733/problem/D
题意:

给定n个长方体,求一个最大的内切球的半径,可以是两块石头将两个完全匹配的面合起来的或者就用一块石头,输出切出最大内切球的那1/2个石头是哪些。

分析:

一个立方体得到一个球,那么限制球半径大小的是最小的边长。
考虑一个立方体,那么最优一定是max(min(a[i],b[i],c[i]))
考虑2个立方体,如果想更大,一定是去合并最小的边,使最小边变大,这样答案就有可能变大。
要想合并最小的边,那么另外两条边就要相等。所以先按照另外两条边排序,这样在判断一下两个立方体的两条边是否相等,如果相等在判断是否合并后更大即可。

比赛的时候想复杂了,认为对于当前i立方体,二分找到他可以合并的最小边最大的那个立方体,然后再合并这两个。其实根本没必要,因为最优的情况,一定是相临的2个可以合并的立方体,因为排序后肯定最小的边递增嘛(在可以合并的一段中)。
所以下面的代码把二分去掉,直接判断i和i+1是否可以合并即可。

看到一种很简单的方法:(来自:blog.csdn.net/fsss_7/article/details/52995389
我们先考虑用一块石头的最大内切球半径,一定是ans=max(min(a,b,c))。令a<=b<=c,那么如果我们想用两块石头来优化ans那么一定需要两块石头的b1c1和b2c2那个面,因为如果在这个合并的面内有a的话那么答案一定不会更优,所以我们用一个二维map存一下之前map[b][c]的最大的a即可,然后去判断合并的min(a+map[b][c],b)是否能更新ans即可。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int INF=0x3f3f3f3f;
const int N=1e5+9;
int s[N];
int a[11],n;
struct point
{
    int a,b,c,idx;
    bool operator < (const point& rhs)const{
        if(c==rhs.c&&b==rhs.b)return a<rhs.a;
        if(c==rhs.c)return b<rhs.b;
        return c<rhs.c;
    }
};
point p[N],p1[N];

int powb(int x,int y,int v)
{
    int m;
    while(x<y){
        m=x+(y-x+1)/2;
        if(p[m].b<=v)x=m;
        else y=m-1;
    }
    return x;
}
int powc(int x,int y,int v)
{
    int m;
    while(x<y){
        m=x+(y-x+1)/2;
        if(p[m].c<=v)x=m;
        else y=m-1;
    }
    return x;
}
int main()
{
    //freopen("f.txt","r",stdin);
    scanf("%d",&n);
    int ans=0;
    int idx1,idx;
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&a[0],&a[1],&a[2]);
        sort(a,a+3);
        p[i].a=a[0];
        p[i].b=a[1];
        p[i].c=a[2];
        p[i].idx=i;

        if(a[0]>ans)ans=a[0],idx=i;
    }
    sort(p+1,p+1+n);
    bool flag=0;
    for(int i=1;i<=n;i++){
        //cout<<p[i].c<<' '<<p1[i].c<<endl;
        int x=powc(i,n,p[i].c);
        int y=powb(i,x,p[i].b);
        if(y>i&&(ans<p[i].a+p[y].a&&ans<p[i].b)){
            flag=1;
            ans=min(p[i].b,p[i].a+p[y].a);
                idx=p[i].idx;
                idx1=p[y].idx;
        }
    }
    if(flag){
        puts("2");
        printf("%d %d\n",idx,idx1);
    }
    else{
        puts("1");
        printf("%d\n",idx);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值