【NOIP2016提高A组集训第8场11.5】心理学概论

25 篇文章 0 订阅

Description

上了大学之后,小W和小Z一起报了一门虐课,在课本上遇到了一份关于嫉妒的案例。
很久很久以前,森林里住着一群兔子。
其中有三只兔子,第一只兔子喜欢吃萝卜,第二只兔子喜欢吃青菜,第三只兔子喜欢吃三文鱼中卷寿司。
有一天,他们收集了 n 个篮子的食物,其中每个篮子里恰好装了一只萝卜,一捆青菜和一个三文鱼中卷寿司,每个食物都有一个美味度。然后他们打算分吃篮子里的食物。如果第一只兔子得到了一些篮子,那么他只会吃每个篮子里面的胡萝卜,然后它获得的美味度即为它吃到的美味度最大的胡萝卜。同理第二只兔子只会吃青菜,第三只兔子只吃三文鱼中卷寿司,同时他们也分别能获得一个美味度。
出于嫉妒心,其余的没有食物的兔子希望计算,如果给这三只兔子划分篮子,使得他们三人获得的美味值之和最小。注意每个篮子是最小的划分单位,不能把篮子里的食物拿出来和放入新食物。如果一个兔子没有得到任何篮子,那么它获得的美味度为0。

Solution

比赛的时候,我直接打上了贪心,但是很快就举出了反例。然后,我打了7个贪心取最小值。结果还是错的。
我想了一下双二分,二分a的位置,然后在里面套上一个二分b的位置,然后O(n)求出c,更新答案。
有一群人打暴力竟然过了这些水数据。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
ll i,j,k,l,n,m,ans1,ans2,ans3,r,mid,lo,ro,mido;
ll ans,x,y,z,t,o;
bool bz;
const int maxn=100007;
struct node{
    ll a,b,c,d;
}a[maxn];
bool cmp1(node x,node y){return x.a<y.a||x.a==y.a&&x.b<y.b||x.a==y.a&&x.b==y.b&&x.c<y.c;}
int main(){
    freopen("psy.in","r",stdin);
    freopen("psy.out","w",stdout);
    scanf("%lld",&n);
    fo(i,1,n){
        scanf("%lld%lld%lld",&a[i].a,&a[i].b,&a[i].c);
        ans1=max(a[i].a,ans1);ans2=max(a[i].b,ans2);ans3=max(ans3,a[i].c);
        a[i].d=min(a[i].a,min(a[i].b,a[i].c));
    }
    ans=min(ans1,min(ans2,ans3));
    sort(a+1,a+1+n,cmp1);
    l=0,r=n;
    while(l<r){
        mid=(l+r)/2;
        lo=0,ro=n;
        bz=1;
        while(lo<ro){
            mido=(lo+ro)/2;
            if(mido==mid){
                if(mido+1!=r)mido++;
                else if(mido-1!=l)mido--;
                else{
                    bz=0;
                    break;
                }
            }
            k=0;
            fo(i,1,n){
                if(a[i].a<=a[mid].a)continue;   
                if(a[i].b<=a[mido].b)continue;
                if(a[i].c>k)k=a[i].c;
            }
            ans1=a[mid].a+a[mido].b+k;
            if(ans1<ans){
                ans=ans1;
                bz=1;
                ro=mido;
            }
            else lo=mido+1;
        }
        if(bz)r=mid;else l=mid+1;
    }
    k=0;
    fo(i,1,n){
        if(a[i].a<=a[l].a)continue;   
        if(a[i].b<=a[lo].b)continue;
        if(a[i].c>k)k=a[i].c;
    }
    ans=min(ans,a[l].a+a[lo].b+k);
    printf("%lld\n",ans);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值