Bad Juice

Toyota Programming Contest 2024#1(AtCoder Beginner Contest 337)
E - Bad Juice
题目链接

题目:

这是一个交互题(一种和评测程序通过标准输入输出进行交互的问题)

N N N ( 2 ≤ N ≤ 100 ) (2\le N \le 100) (2N100)瓶果汁,编号从 1 1 1 N N N。有一瓶坏了,喝一小口第二天就会胃疼。

Takahashi必须在下一天辨别出哪一瓶是坏的。为此,他要叫最少的朋友来来喝他的果汁。他可以给每个朋友任意瓶任意编号的果汁。

输出要叫几个朋友和如何分发果汁。第二天收到朋友拉肚子的消息,并打印出坏掉的果汁编号。

交互:

在交互之前,坏果汁的编号会被秘密确定,不会告诉你,坏果汁的编号在交互过程中可以更改,不过一定会保证它不会和先前的输出冲突。

首先会给你一个数 N N N

紧接着一行你需要打印一个数 M M M,表示最小要叫几个朋友。

然后,你要执行接下来的过程,并输出 M M M 个结果:
i = 1 , 2 , … , M i=1,2,…,M i=1,2,,M ,第 i i i 行输出包括你要给第 i i i 个朋友的饮料瓶数和每瓶饮料的编号,编号满足单调递增

然后评测程序会给你一个长为 M M M 的01字符串 S S S ,对 i = 1 , 2 , … , M i=1,2,…,M i=1,2,,M S i = 1 S_i=1 Si=1 表示第 i i i 个朋友闹肚子。

然后你需要打印坏果汁的编号,如果你给出的答案中朋友数确实是最小的,而且答案唯一,程序才被认为是正确的。

思路:

这又是哪家的面试题()

考虑模仿一下二分的思想,比如有8瓶果汁,假如从0开始编号,第一个朋友喝前一半,如果闹肚子了,说明坏果汁在前一半里,否则就在后一半里。对第二个朋友,由于0 ~ 3 和 4 ~ 7 的果汁不会相互影响,所以我们可以让他喝每一个的前一半,也就是0 1 和 4 5 ,这样范围就又缩小了一半。

找找规律,发现第一个朋友喝的果汁编号二进制第3位一定是0,第二个朋友喝的果汁编号第2位一定是0,第一个朋友喝的果汁编号第1位一定是0。其实也好理解,第 i i i 个朋友喝掉全部编号第 i i i 位为0的果汁,如果第 i i i 个朋友拉肚子了,二进制第 i i i 位这里一定是0,否则是1,一位一位确定。因此最少需要 M = ⌈ log ⁡ 2 N ⌉ M=\lceil \log_2N \rceil M=log2N 个朋友。

不过这里编号是从1开始的,所以算的时候用0 ~ N-1,输出的时候编号要加1。

之前看过一个很像的面试题,就是有n瓶水,一瓶有毒,问最少用几种小白鼠可以一次试出来哪瓶有毒。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=105;

int n,x,t;
int a[maxn];

int main(){
	cin>>n;
	x=ceil(log2(n));
	cout<<x<<endl;
	for(int i=x-1;i>=0;i--){
		a[0]=0;
		for(int j=0;j<n;j++){
			if(!(j&(1<<i)))//第i位为0 
				a[++a[0]]=j;
		}
		printf("%d ",a[0]);
		for(int j=1;j<=a[0];j++)
			cout<<a[j]+1<<" ";
		cout<<endl;
	}
	string s;
	cin>>s;
	reverse(s.begin(),s.end());
	int ans=0;
	for(int i=x-1;i>=0;i--)
		if(s[i]=='0')ans|=(1<<i);
	cout<<ans+1<<endl;
	return 0;
}
  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值