您的位置:首页 > 其它

所有可能的连续自然数(两个以上)之和的算式

2011-05-25 21:39 197 查看
注:leoyonn原创,请注明出处 http://hi.baidu.com/leoyonn

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

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

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

------------------------------------------------------------------------------------------------------------

解答1. 首先分析,

对于正整数N,如果表示成2个连续自然数相加,N = m + (m + 1) = 2m + 1,则N为奇数;

如果表示成3个连续的自然数相加,N = (m - 1) + m + (m + 1) = 3m,则N为3的倍数;

如果表示成4个连续的自然数相加,N = (m - 1) + m + (m + 1) + (m + 2) = 2 * (2m + 1),则N为某奇数的2倍;

如果表示成5个连续的自然数相加,……,则N为5的倍数;

如果表示成5个连续的自然数相加,……,则N为某奇数的3倍;

……

已经找到规律了:对于N,

如果表示成偶数个(2 * k) 连续的自然数相加, 则N为k的倍数;

如果表示成奇数个(2 * k + 1)连续的自然数相加, 则N为(2 * k + 1)的倍数。

这样程序就好写啦:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

bool AddSubN(__int64 N)
{
if(N < 3)
{
printf("No sequences fit N./n");
return false;
}
bool bFind = false;
int num = 0;
printf("/n %I64d ./n", N);

__int64 maxLoop = sqrt(2 * N);
//当N = 1 + 2 + ... + m = m * (m + 1) / 2时的序列长度最大,
//所以maxLoop比这个小
//注意:这里可能得用大整数开方,我懒得写了

__int64 i, j, testN;
// 看N是否能被表达成 i 个连续自然数之和
for(i = 2; i <= maxLoop; i ++)
{
if(!(i & 0x1))  //如果 i 是偶数,则N为 i/2 的倍数,且 N /(i/2) 为奇数;
{
if((!(N % (i >> 1))) && ((N / (i >> 1))) & 1)
{
__int64 sub0 = (N / (i >> 1) - 1) / 2;    // i 个数中,中间偏左的一个
sub0 -= i / 2 - 1;                      // i 个数中最左边的一个
testN = 0;
for(j = 0; j < i; j ++)
testN += sub0 + j;
//打印出来,测试是否跟输入的N一样
printf("/n %I64d = ", N, testN);

//打印连续自然数序列
for(j = 0; j < i - 1; j ++)
printf("%I64d + ", sub0 + j);
printf("%I64d ./n", sub0 + j);

if(!bFind)
bFind = true;
num ++;

}
}
else        // 如果 i 是奇数,则N为 i 的倍数
{
if(!(N % i))
{
__int64 sub0 = N / i;
sub0 -= i / 2;          //找到i个数中最左边的一个

testN = 0;
for(j = 0; j < i; j ++)
testN += sub0 + j;
//打印出来,测试是否跟输入的N一样
printf("/n %I64d = ", N, testN);

//打印连续自然数序列
for(j = 0; j < i - 1; j ++)
printf("%I64d + ", sub0 + j);
printf("%I64d ./n", sub0 + j);

if(!bFind)
bFind = true;

num ++;
}
}
}
if(!bFind)
{
printf("No sequences fit N./n");
return false;
}

printf("/n---------------/n %d sequences fit N found ./n", num);

return true;
}

void main()
{
__int64 N = 3;
while(N >= 1)
{
printf("Please input a int64 number. (input 0 or -1 to escape)/n");
scanf("%I64d", &N);
system("cls");
AddSubN(N);
printf("/n/n/n");
system("pause");
system("cls");
}
}
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

bool AddSubN(__int64 N)
{
if(N < 3)
{
printf("No sequences fit N./n");
return false;
}
bool bFind = false;
int num = 0;
printf("/n %I64d ./n", N);

__int64 maxLoop = sqrt(2 * N);
//当N = 1 + 2 + ... + m = m * (m + 1) / 2时的序列长度最大,
//所以maxLoop比这个小
//注意:这里可能得用大整数开方,我懒得写了

__int64 i, j, testN;
// 看N是否能被表达成 i 个连续自然数之和
for(i = 2; i <= maxLoop; i ++)
{
if(!(i & 0x1)) //如果 i 是偶数,则N为 i/2 的倍数,且 N /(i/2) 为奇数;
{
if((!(N % (i >> 1))) && ((N / (i >> 1))) & 1)
{
__int64 sub0 = (N / (i >> 1) - 1) / 2; // i 个数中,中间偏左的一个
sub0 -= i / 2 - 1;      // i 个数中最左边的一个
testN = 0;
for(j = 0; j < i; j ++)
testN += sub0 + j;
//打印出来,测试是否跟输入的N一样
printf("/n %I64d = ", N, testN);

//打印连续自然数序列
for(j = 0; j < i - 1; j ++)
printf("%I64d + ", sub0 + j);
printf("%I64d ./n", sub0 + j);

if(!bFind)
bFind = true;
num ++;

}
}
else  // 如果 i 是奇数,则N为 i 的倍数
{
if(!(N % i))
{
__int64 sub0 = N / i;
sub0 -= i / 2;   //找到i个数中最左边的一个

testN = 0;
for(j = 0; j < i; j ++)
testN += sub0 + j;
//打印出来,测试是否跟输入的N一样
printf("/n %I64d = ", N, testN);

//打印连续自然数序列
for(j = 0; j < i - 1; j ++)
printf("%I64d + ", sub0 + j);
printf("%I64d ./n", sub0 + j);

if(!bFind)
bFind = true;

num ++;
}
}
}
if(!bFind)
{
printf("No sequences fit N./n");
return false;
}

printf("/n---------------/n %d sequences fit N found ./n", num);

return true;
}

void main()
{
__int64 N = 3;
while(N >= 1)
{
printf("Please input a int64 number. (input 0 or -1 to escape)/n");
scanf("%I64d", &N);
system("cls");
AddSubN(N);
printf("/n/n/n");
system("pause");
system("cls");
}
}


------------------------------------------------------------------------------------------------------------

解答2. 从分析中可以看出,N的因式分解必然要有奇数。证明如下:

a. 首先证明,只要N的因式分解中有奇数,N就能表示为自然数连和。

如果N的因式分解中有奇数,假设为s,且N= k * s,

如果k > s/2,

则 N可以表示为这个序列的和:k - (s / 2), k - (s / 2) + 1 ... k + (s / 2);

例如 54 = 6 x 9, 可表示为 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10;(6 x 9,偶数为6,则6在这9个自然数的序列的中间)

如果 k < s/2,

则N可以表示为这个序列的和:(s + 1)/2 - k, (s+1)/2 - k + 1,..., (s + 1)/2 + k - 1;

如54 = 2 x 27,则可表示为 12 + 13 + 14 + 15;(中间两个数 13 + 14 = 27)

b. 再证明:如果N的因式分解中没有奇数,则N不能表示成连和的形式。

反证:如果能,假设N能表示成k个自然数的连和。

如果k为偶数,设这k个数的中数(中间偏左的一个)为m,将这k个数收尾相加得到k/2个自然数的序列,

易证这k/2个自然数都等于2m+1,

那么N = (2m + 1) * k / 2,与N的因式分解中没有奇数矛盾;

如果k为奇数,设中数为n,那么N = k * n,与N的因式分解中没有奇数矛盾。

综上,得证。

------------------------------------------------------------------------------------------------------------

解答3.

从2的推导过程中想到,将N表达成X*Y的形式,Y为奇数(X可以为1),这种表达形式越多,N的连和序列就越多。

这样,将N分解为质因子,例如150 = 2 * 3 * 5 * 5,找到其中所有的奇数,这些奇数能构成的组合数就是N的连和数。

如3,5,5能构成3;5;3*5;5*5;3*5*5,共5种,所以N的连和数也是5个。经验证,正确,嘿嘿。

再进一步想,已经知道N的质因子分解情况,怎么计算有多少个序列?

例如3*5,有3,5,3*5,共3种;

而3*3*5,上面已经说过,共5中;

3*3*3*5,有3,3*3,3*3*3,5,3*5,3*3*5,3*3*3*5,共7种……

总结得到:

假设N的质因子分解中有k种奇数(不是k个)记为odd[1,..,k],odd[i]有n[i]个,那么N能表示的序列数为:

Ns = (n[0] + 1) * (n[2] + 1) * (n[3] + 1) * ... * (n[k] + 1) - 1

验证:3*3*3*3*5*5*7*7*7 = 694575,我用程序打印,输出了59个。

这里有4个3,2个5,3个7,(4+1)*(2+1)*(3+1) - 1 = 60 - 1 = 59,验证成功。而694575乘以2的任意幂次方,所得结果都是59.

我这没有想到严格的逻辑证明这个思路得到的结果是正确的,呵呵。

接下来就可以思考第三题了:在64位正整数中,子序列数目最多的是哪一个?

已经知道,要求的就是要让子序列数目最多Ns最多,但是64位正整数中“最”多的是谁?首先是一个很大的奇数^^。

这里我又做一个实验:

3*5*7*13 = 1365,分解出的连和15个;

3*3*5*5*7 = 1575,有17个,

3*3*3*3*3*7 = 1701, 有11个;

到底哪种组合能够达到最多的那个?这个我没想出来…… 各位有想法的还请不吝赐教:)

呵呵,个人想法,欢迎拍砖,指正:)

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lyso1/archive/2010/03/20/5399146.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐