51nod 1837 砝码称重【数学,规律】

题目链接:51nod 1837 砝码称重

小 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

题解:最先猜到1,3,6,10,15这些数比较特殊,都只要称一次,因为:

3=1+2,6=1+2+3,10=1+2+3+4......

然后猜想其他数应该和其组合有关,比如5=1+4和2+3,然后4里面有1+2和1+3(事实上只要124,判断1+2<4就行了),然后猜测要称的次数和最大砝码的加法组合有关(必须有一边要放一个,因为题目说要确定哪个错了,唔其实这里开始就想错了)。。然后,没猜出来。。。其中还猜想过答案只有1和2吧,但是我不会证明吖QAQ,后面越算越糊涂,弃疗。。。

不扯了,,,花个点头盾,

来看正解:(答案就是只有1和2哎。。。高斯证明过任意一个正整数可以表示成三个三角形数的和)

①如上猜想,1,3,6,10这样的三角形数k*(k+1)/2,都只要一次,选出k个数之和判断是否与n相等即可,因为任选k个数组成的最小质量和是n。

②n 等于 三角形数+1的也只要一次,与上同理,判断选出k个数是否<n即可

③当第n个三角形数是平方数时,只要一次,判断1+2+...+(k-1)=(k+1)+(k+2)+...+n是否成立,因为去掉一个砝码后能够拆分成两个质量和相同的砝码区间只有一种方案。

当第n个三角形数是平方数+1时,只要一次,与上同理。

⑤其他情况,n,n-1,n-2中至少有一个数可以表示成两个三角形数的和,从而只需要称两次,因为小于号可以使用至多两次。

(判断一个数是不是平方数只需要将其开根下取整再平方进行检验,判断三角形数同理。)

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 typedef long long ll;
 5 ll n, t, k, kk;
 6 int main() {
 7     while(~scanf("%lld", &n)){
 8         if(n==1) {puts("0");continue;}
 9         k = sqrt(2*n-1);
10         t = n*(n+1)/2; kk = sqrt(t);
11         if(k*(k+1)/2 == n || k*(k+1)/2 + 1 == n ||
12            t == kk*kk || t == kk*kk+1) puts("1");
13         else puts("2");
14     }
15     return 0;
16 }
234ms
原文地址:https://www.cnblogs.com/GraceSkyer/p/7620323.html