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

来源:互联网 发布:图片透视软件 编辑:程序博客网 时间:2024/04/30 20:24

题目:

我们知道: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。
 
代码:
#include<iostream>using namespace std;void AddNum(__int64 num){__int64 k;__int64 i,t;__int64 j;int flag=-1;for (k=2;num>j;k++)//判断条件也可用sqrt(2*num),但是sqrt对64位的不好用。{if (k%2==0){j=(k/2)*(k-1);//这样判断是为了节省计算的时间,因为k*(k-1)/2比(k/2)*(k-1)更费时间} else{j=((k-1)/2)*k;}if (((num-j)%k)==0){flag=1;i=(num-j)/k;}if (flag==1){printf("%I64d = ",num);for (t=0;t<k;t++){printf("%I64d",i+t);if ((t+1)<k){printf(" + ");} }flag=0;cout<<endl;}if ((k+1)%2==0){j=((k+1)/2)*k;} else{j=(k/2)*(k+1);}}if (flag==-1){printf("%I64d不可以表示成连续的自然数\n",num);} }void main(){__int64 num;cout<<"请输入一个64位正整数:"<<endl;//cin>>num;  编译出错,cin适合32位的scanf("%I64d",&num);AddNum(num);}
 

 

第二题:
解题思路:
因为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