游戏
以下是原题
【问题描述】
/*“Ran,今天我要在Hakase 家打游戏,不回来了。”
“Ran,Hakase 新发明了游戏,我今天住博士家。”
“Ran,Conan 今天要在我家通宵打游戏。”
终于有一天,电脑被打坏了……2333
所以Conan 要前往专卖店买新的,正好专卖店正在促销,*/
一共有三种礼包:
豪华礼包:一个U 盘、一个鼠标和一个机械键盘。
幸运礼包:一个U 盘、两个鼠标。
普通礼包:两个U 盘、一个鼠标。
卖店内准备了a 个U 盘、b 个鼠标和c 个机械键盘。为了给顾客带来足
够多的惊喜,店长希望相邻两位领礼包的顾客拿到的礼包类型都是不同的。店长
想知道这些奖品最多可以发出多少份礼包。可是店长毕竟没有Conan 聪明,所以
请教Conan,可是Conan 要急着回去打游戏,所以就交给你啦。
【输入格式】
从文件store.in 中读入数据。
输入第一行包含一个正整数T。
接下来T 行每行包含3 个正整数a, b, c,依次表示U 盘、鼠标和机械键盘各
有多少个。
【输出格式】
输出到文件store.out 中。
输出T 行,每行一个整数,表示最多能发出多少份礼包。
【样例输入】
24
4 0
1 1 1
【样例输出】
2
1
【数据规模与约定】
对于 30%的数据满足T<=10,a,b,c<=30。
对于 60%的数据满足T<=100,a,b,c<=300,000。
对于 100%的数据满足T<=100000,0<=a,b,c<=1,000,000。
====================分==============割================线========================
所以实际上这道题实际上就是有a个U盘,b个鼠标,c个键盘,将它们分成不连续的三种礼包,求最多能分出多少礼包。
首先根据数据范围算复杂度,⑩万的数据最大也就只能用O(n*logn)左右的算法了。答案仅为最多礼包数,T组数据,
所以二分枚举答案是首选。接下来就是如何检验枚举出来的数是否成立了,对于我们枚举出的x,
在满足相邻礼包不相同的条件下,三种礼包中 (送出礼包数较小两种的礼包数量之和)>=x/2。再来看这三种礼包:
U盘 | 鼠标 | 机械键盘 | |
豪华礼包 | 1 | 1 | 1 |
幸运礼包 | 1 | 2 | |
普通礼包 | 2 | 1 |
不难发现,每一种礼包都是一个U盘、一个鼠标,再加上 { U盘、鼠标、机械键盘 } 中三选一构成,
就是说每个礼包的保底是1个U盘和1个鼠标,外加上三选一,
所以验证方法实际上就出来了:
a个U盘,b个鼠标,c个键盘,枚举的x个礼包,首先需要a>=x,b>=x,
然后a,b都减去x,剩余a,b,c的值就是对应的普通、幸运、豪华礼包个数,
a,b,c中两两相加之和最小的如果>=x/2,则此方案成立。
#include<cstdio>
int T,a,b,c,l,r,mid,ans;
bool ch(int x)
{
int a1=a,b1=b,c1=c;
a1-=x;b1-=x;
if(a1<0||b1<0)return 0;
int mi=a1+b1;
if(a1+c1<mi)mi=a1+c1;
if(b1+c1<mi)mi=b1+c1;
if(mi<x/2)return 0;
return 1;
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&a,&b,&c);
l=0;r=(a+b+c)/3;mid=(l+r)/2;
while(l+5<r)//二分时左右间距开到5会容错率高一点(笑
{
if(!ch(mid))r=mid-1;
else l=mid;
mid=(l+r)/2;
}ans=l;
for(int i=l;i<=r;i++)
{
if(!ch(i))break;
ans=i;
}
printf("%d
",ans);
}
}
//高中生来水普及组的题真™丢人