正整数分解为几个连续自然数之和

简介: /* 小提示:判断一个数是否是2的方幂 n > 0 && ((n & (n - 1)) == 0 ) 题目:输入一个正整数,若该数能用几个连续正整数之和表示,则输出所有可能的正整数序列。 一个正整数有可能可以被表示为n(n>=2)个连续正整数之和,如: 15=1+2+3+4+5 1...
/*
小提示:判断一个数是否是2的方幂 n > 0 && ((n & (n - 1)) == 0 )
题目:输入一个正整数,若该数能用几个连续正整数之和表示,则输出所有可能的正整数序列。

一个正整数有可能可以被表示为n(n>=2)个连续正整数之和,如:
15=1+2+3+4+5
15=4+5+6
15=7+8

有些数可以写成连续N(>1)个自然数之和,比如14=2+3+4+5;有些不能,比如8.那么如何判断一个数是否可以写成连续N个自然数之和呢?
一个数M若可以写成以a开头的连续n个自然数之和,则M=a+(a+1)+(a+2)+…+(a+n-1)=n*a+n*(n-1)/2,要求a!=0,否则就是以a+1开头的连续n-1个整数了,
也就是要求(M-(n+n*(n-1)/2))%n==0,(令%左边卫kn则m=(k+1)n+n*(n-1)/2)(k>=0),就和原来一样啦),即(M-(n*(n+1)/2))%n==0,
这样就很容易判断一个数可不可以写成连续n个自然数的形式了,遍历n=2…sqrt(M)*2,(个人认为小于等于m/2+1或者sqrt(2*m)才是正解)还可以输出所有解。
*/
void divide(int num)  
{  
    int i,j,a;  
    for(i=2; i<=sqrt((float)num)*2; ++i)  
    {  
        if((num-i*(i-1)/2)%i==0)  
        {  
            a=(num-i*(i-1)/2)/i;  
            if(a>0)  
            {  
                for(j=0; j<i; ++j)  
                    cout<<a+j<<" ";  
            }  
            cout<<endl;  
        }  
    }   
} 
/*
第二个问题是什么样的数可以写成连续n个自然数之和,什么样的数不能?

通过编程实验发现,除了2^n以外,其余所有数都可以写成该形式。下面说明为什么。
若数M符合条件,则有M=a+(a+1)+(a+2)+…+(a+n-1)=(2*a+n-1)*n/2,而2*a+n-1与n肯定一个为奇数一个为偶数,即M一定要有一个奇数因子,而所有2^n都没有奇数因子,因此肯定不符合条件。
再证明只有M有一个奇数因子,即M!=2^n,M就可以写成连续n个自然数之和。假设M有一个奇数因子a,则M=a*b。

若b也是奇数,只要b-(a-1)/2>0,M就可以写成以b-(a-1)/2开头的连续a个自然数;将这条结论里的a和b调换,仍然成立。15=3*5=1+2+3+4+5=4+5+6. 
若b是偶数,则我们有一个奇数a和一个偶数b。 
2.1 若b-(a-1)/2>0,M就可以写成以b-(a-1)/2开头的连续a个自然数。24=3*8=7+8+9. 
2.2 若(a+1)/2-b>0,M就可以写成以(a+1)/2-b开头的连续2*b个自然数。38=19*2=8+9+10+11. 
上述两个不等式必然至少有一个成立,所以可以证明,只要M有一个奇数因子,就一定可以写成连续n个自然数之和。

另一个正整数分解的算法:
sum(i,j)为i累加到j的和 
令 i=1 j=2 
if sum(i,j)>N i++ 
else if sum(i,j)<N j++ 
else cout i...j 

*/
#include <iostream>   
using namespace std;  
  
int add(int m,int n)  
{  
    int sum=0;  
    for(int i=m;i<=n;i++)  
        sum+=i;  
    return sum;  
}  
  
void divide(int num)  
{  
    int i=1,j=2,flag;  
    int sum=0;  
    while(i<=num/2)  
    {  
     sum=add(i,j);  
     while(sum!=num) //一定存在解,所以不会死循环 
     {  
        if(sum>num)  
            i++;  
        else  
            j++;  
        sum=add(i,j);  
     }  
     for(int k=i;k<=j;k++)  
        cout<<k<<" ";  
     ++i;  
     cout<<endl;  
    }  
}  
  
int main()  
{  
    int num;  
    cout<<"Please input your number:"<<endl;  
    cin>>num;  
    divide(num);  
    return 0;  
}

 

目录
相关文章
|
7月前
|
算法
求连续整数的阶层的和,时间复杂程度为O(n)的解法
求连续整数的阶层的和,时间复杂程度为O(n)的解法
|
7月前
|
算法 测试技术 C#
【位运算 拆位法 二分】3007. 价值和小于等于 K 的最大数字
【位运算 拆位法 二分】3007. 价值和小于等于 K 的最大数字
|
7月前
每日一题来噜!(记负均正,旋转数组中的最小数字)
每日一题来噜!(记负均正,旋转数组中的最小数字)
34 1
|
7月前
每日一题(最大连续1的个数,完全数计算)
每日一题(最大连续1的个数,完全数计算)
37 0
|
7月前
|
机器学习/深度学习
【剑指offer】-和为S的连续正数序列-39/67
【剑指offer】-和为S的连续正数序列-39/67
剑指offer 64. 和为S的连续正数序列
剑指offer 64. 和为S的连续正数序列
67 0
|
算法
[算法]将一个正整数拆分成若干个正整数的和,输出所有的结果不重复
推荐先看我的一篇介绍Set去重的博文地址是 http://blog.csdn.net/bug_moving 看了这个之后,再来看下面的程序基本就能看懂了 题目 我也不太记得,因为是朋友给我口述的,然后给了我一个截图,看了图片大致也能知道题目要我们做什么 package yn; import java.util.ArrayList; import java.
2818 0
57_和为s的连续正数序列
57_和为s的连续正数序列
106 0
|
算法
每日一练(30):和为s的连续正数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
107 0