51nod 1837 砝码称重【数学,规律】
小 Q 有 n 个砝码,它们的质量分别为 1 克、 2 克、……、 n 克。
输入包含多组测试数据。 每行对应一组测试数据,包含一个正整数 n 。 不超过 10^5 组数据,1 ≤ n ≤ 10^9。
每行对应一组测试数据,输出一个正整数表示答案。
1 5 6
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 }