1837 砝码称重
Description
小 Q 有 n 个砝码,它们的质量分别为 1 克、 2 克、……、 n 克。
他给 i 克的砝码标上了编号 i (i = 1, 2, …, n),但是编号被人打乱了,即编号为 i 的砝码不一定是 i 克,而是 a_i 克,这里 a 指的是 1 到 n 的一个排列。
他有一杆天平,可以向天平的两侧放任意数量的砝码,通过一次称量得到两侧质量的大小关系,关系只有左侧重、一样重、右侧重三种可能。
他想知道,最坏情况下,他至少需要称量多少次,才能确定其中至少一个编号为 i 的砝码的质量是 i 克或不是 i 克。
提示:这里所谓的最坏情况是指,对于固定的、按顺序进行的称量操作,不论每次称量的结果是什么,都能完成所需完成的上述判定任务。
例如 n = 6 时,可以只称量一次,选择编号为 1、 2、 3 的砝码放在左侧,编号为 6 的砝码放在右侧。
如果天平不是平的,则可以确定存在至少一个砝码 i 不是 i 克 (i = 1, 2, 3, 6),否则编号为 6 的砝码一定是 6 克。
再例如 n = 5 时,可以只称量两次,第一次选择编号为 2、3 的砝码放在左侧,编号为 5 的砝码放在右侧,第二次选择编号为 1、4 的砝码放在左侧,编号为 5 的砝码放在右侧。
这里略去这样称量的正确性,留给做题人推导和证明。
Input
输入包含多组测试数据。
每行对应一组测试数据,包含一个正整数 n 。
不超过 10^5 组数据,1 ≤ n ≤ 10^9。
Output
每行对应一组测试数据,输出一个正整数表示答案。
Input示例
1
5
6
Output示例
0
2
1
Solution
马拉松的t1,一开始以为是一道打卡题,结果题目读了半天才勉强理解题意,比赛的时候没打出来,直到结束,看了大神的解释,才渐渐理解,赛后第三个AC了此题,拿到了51nod第一枚牌子(虽然是铜牌)其实弄懂规律以后题目还是好做的,易想到最多两次便可以称出来,但具体是一次还是两次(当然,只有一个砝码的时候是0次),所以我们要分四种情况考虑,具体详见代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
long long n;
int gauss(int x){
long long l=1,r=1000000000;
while(l<r){
long long mid=(l+r+1)/2;
if (mid*(mid+1)<=1ll*2*x) l=mid;
else r=mid-1;
}
return l;
}
int main(){
while (scanf("%lld",&n)!=EOF){
if (n==1){
printf("0\n");
continue;
}
long long k=gauss(n);
if (k*(k+1)/2==n){
printf("1\n");
continue;
}
else{
k=gauss(n-1);
if (k*(k+1)/2==n-1){
printf("1\n");
continue;
}
long long m=(n+1)*n/2;
long long g=sqrt(1.0*m);
while (g*g<m) g++;
if (g*g==m){
printf("1\n");
continue;
}
m=(n+1)*n/2-1;
g=sqrt(1.0*m);
while (g*g<m) g++;
if (g*g==m){
printf("1\n");
continue;
}
printf("2\n");
}
}
return 0;
}