编程之美----2.21 只考加法的面试题

题目:

我们知道:1+2=3;
             4+5=9;
             2+3+4=9;
等式左边都是两个以上连续的自然数相加,那么是不是所有的整数都可以写成这种形式呢?

问题1. 写一个程序,对于一个64位正整数,输出它所有可能的连续自然数(两个以上)之和的算式;

问题2. 有的数例如32就找不到这样的表达,这样的数字有什么规律?

问题3. 在64位正整数中,子序列数目最多的是哪一个?能否用数学知识推导出来?

 PS: 64位整数为一种数据类型,即是pascal的int64以及c++的long long。能够表达-9223372036854775808到9223372036854775807之间的任意整数。
问题1:
num=i + i+1 + i+2 + ....+ i+k-1  一共有k个数。
= (i + i+k-1)*k/2
=(2*i+k-1)*k/2
=k*(i+ (k-1)/2)
=k*i + k*(k-1)/2
判断条件: num%(k*(k-1)/2)==0 或者 2*num>k*(k-1) 得: k<sqrt(2*num) 
i=num/k;可得出i。
 
代码:
[cpp]  view plain copy
  1. #include<iostream>  
  2. using namespace std;  
  3. void AddNum(__int64 num)  
  4. {  
  5.     __int64 k;  
  6.     __int64 i,t;  
  7.     __int64 j;  
  8.     int flag=-1;  
  9.     for (k=2;num>j;k++)//判断条件也可用sqrt(2*num),但是sqrt对64位的不好用。  
  10.     {  
  11.         if (k%2==0)  
  12.         {  
  13.             j=(k/2)*(k-1);//这样判断是为了节省计算的时间,因为k*(k-1)/2比(k/2)*(k-1)更费时间  
  14.         }   
  15.         else  
  16.         {  
  17.             j=((k-1)/2)*k;  
  18.         }  
  19.         if (((num-j)%k)==0)  
  20.         {  
  21.             flag=1;  
  22.             i=(num-j)/k;  
  23.         }  
  24.         if (flag==1)  
  25.         {  
  26.             printf("%I64d = ",num);  
  27.             for (t=0;t<k;t++)  
  28.             {  
  29.                 printf("%I64d",i+t);  
  30.                 if ((t+1)<k)  
  31.                 {  
  32.                     printf(" + ");  
  33.                 }             
  34.             }  
  35.             flag=0;  
  36.             cout<<endl;  
  37.         }  
  38.         if ((k+1)%2==0)  
  39.         {  
  40.             j=((k+1)/2)*k;  
  41.         }   
  42.         else  
  43.         {  
  44.             j=(k/2)*(k+1);  
  45.         }  
  46.     }  
  47.     if (flag==-1)  
  48.     {  
  49.         printf("%I64d不可以表示成连续的自然数\n",num);  
  50.     }   
  51. }     
  52. void main()  
  53. {  
  54.     __int64 num;  
  55.     cout<<"请输入一个64位正整数:"<<endl;  
  56.     //cin>>num;  编译出错,cin适合32位的  
  57.     scanf("%I64d",&num);  
  58.     AddNum(num);  
  59. }  
 

 

第二题:
解题思路:
因为num=(2*i+k-1)*k/2
接下来分析(2*i + k-1)*k*(1/2)的特征。
2*i为偶数。若k为奇数,k-1为偶数。则(2*i + k-1)*(1/2) 是一个整数。设为X。则num=k * X =奇数 *  X .
2*i为偶数。若k为偶数,k-1为奇数。则(2*i + k-1)为奇数。则 k*(1/2)  是一个整数。设为X。则num=(2*i + k-1) * X =奇数 *  X .
由此可见,num的因式分解中必须含有一个奇数才可以表达成连续自然数相加的形式。
 
反证法:
如果num的因式分解中不含有奇数。设num= a * b .并且a 、b为偶数。
设a=(2*i +k-1) ,b=k/2.  因为b为偶数,所以k为偶数。得出k-1为奇数。即(2*i +k-1)为奇数。这与a是偶数矛盾。
设a=(2*i +k-1) /2,b=k.  因为a为偶数,所以(2*i +k-1)为偶数。得出k-1为偶数。即k为奇数。这与b是偶数矛盾。

从程序输出结果上来看:
 
由此推理得:这些数都是2的n次方。只要是2的n次方就不能转化成各个自然数连续相加的情形。
第三题
解题思路:
 
8位数中子序列最大的数是:(22个子序列)253 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17+ 18 + 19 + 20 + 21 + 22
16位数中子序列最大的数是:(361个子序列)65341 = 1 + 2 + 3 + 。。。。+ 358 + 359 + 360 + 361 

 。。。。。

设64位数中最大的子序列数位X。有k个子序列。

则X=1+2+3+。。。。+K=K*(1+K)/2

8位数:k*(k+1)/2 <0xFF 得到方程: k^2 + k -512 < 0 ,解方程得 k <22.13.   取k=22.   从1+2+。。。+22就可以得到想要得到的数。

对于64位的数。同样利用上面的方程:k*(k+1)/2 <0xFFFFFFFFFFFFFFFF 得到方程: k^2 + k - (2*0xFFFFFFFFFFFFFFFF) < 0.

解方程得到: k <=6074000999   则num= 18446744070963499500

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值