zoukankan      html  css  js  c++  java
  • 求输出和为n的所有连续自然数序列

    这是编程之美中的一道题。编程之美中的题目是这样的:

    1+2=3

    4+5=9

    2+3+4=9

    等式的左边都是两个或者两个以上的连续自然数相加,那么是不是所有的整数都可以写成这样的形式?

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

    问题2:哪些数字不能不能表示成连续自然数之和?能否证明。

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

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

    问题1:

    这个最先想到方法就是蛮力法。对于一个i (1<i<n)进行测试,看一i开头的自然数序列是不是能得到n这个和。C#代码如下:

    public static void getSequence(int S)
    {
      writer.WriteLine("--------"+S+"---------");
      int sum ;
      for (int i = 1; i < S; i++)
      {
        sum = 0;
      List<int> ns=new List<int>();
      for (int j = i; j <= S&&sum<S; j++)
      {
        sum += j;
        ns.Add(j);
      if (sum == S)
      {
        printArray(ns);
    break;
      }
    }
    }
    }

    这个算法的时间负责度是O(n*n)级别的。

    一些改进可以来对数学公式的应用。

    假设这个连续序列为m,m+1,m+2,…,m+k-1,其中m>0,k>1.那么s=(m+m+k-1)*k/2,2*s=(2*m+k-1)*k.只要找到mk的值,这个序列就可以求出. mk有何关系? 容易发现,(2*m+k-1)k肯定是前者大于后者,并且一个为奇数一个为偶数。因此将2*s进行分解表示为2*s=2^t*a.其中a是个奇数,将a进行因式分解变成a=b*c,那么2*s=2^t*b*c.求出所有2*s的一个奇数和一个偶数的因子分解,就找到了对应的2*m+k-1k,进而能够解出mk.

    下面是上述思想的java实现。

    
    

    public void getSequence(int S){
    System.out.println("------"+S+"------");

    int t=get2(2*S);
    int a=(int)(2*S/Math.pow(2, t));
    if(a==1){
    System.out.println(String.format("%d has no solution", S));
    return;
    }
    ArrayList<Integer[]> pairs=getFactors(a);
    for(Integer[] pa:pairs){
    for(int i=0;i<2;i++){
    int b=pa[i];
    int j=(i+1)%2;
    int c=pa[j];
    int k=0;
    int m=0;
    k=(int)Math.min(Math.pow(2, t)*b,c);
    if(k>1){
    m=(int)(Math.max(Math.pow(2, t)*b,c)-k+1)/2;
    printSequence(S,m,k);
    }
    if(b==c){
    break;
    }
    }
    }
    }

    public ArrayList<Integer[]> getFactors(int a){
    ArrayList<Integer[]> factorPair=new ArrayList<Integer[]>();
    for(int i=1;i<=(int)Math.floor(Math.sqrt(a));i++){
    if(a%i==0){
    Integer[] pair=new Integer[2];
    pair[0]=i;
    pair[1]=a/i;
    factorPair.add(pair);
    }
    }
    return factorPair;
    }

    public int get2(int a){
    int t=0;
    while(a%2==0){
    t++;
    a=a/2;
    }
    return t;
    }

    public void printSequence(int S,int m,int k){
    StringBuilder sb=new StringBuilder();
    sb.append(S);
    sb.append("=");
    for(int i=0;i<k;i++){
    sb.append(m+i);
    sb.append("+");
    }
    String str=sb.toString();
    System.out.println(str.substring(0,str.length()-1));
    }

     从上面的解的过程,我们也发现了问题2的答案。那就是当n为2的幂次方时,n不能够被分解为这样的连续自然数的和的形式。因为这时n=(m+m+k-1)*k/2是无解的。

     关于问题3,看来分解序列最多的生成的a能够分解成不同b*c数最多的那个,注意a是个奇数。64位正整数的范围内,哪个奇数能够产生最多的这样的因式分解?从网上看到这个数应该是3^n这样的形式,因为3是所有质数的最小值,最细刻度的划分,可能会产生最多中划分形式。这样说也有理由,但是不能严谨的证明。而且不用64位,用4位,即n为0到15的正整数,子序列最多的不是9而是15。这样看来3^n不一定正确,但是我觉得这个思路是对的--尽可能的细划分。有时间在研究吧

  • 相关阅读:
    五子棋算法
    记录2个算法知识(常见面试题)
    python基础面试题之类型转换(字典篇)
    Python中的多线程和多进程的应用场景和优缺点。
    python基础面试题之输入年月日,判断这个日期是这一年的第几天。
    Python装饰器(面试题)
    linux终止进程
    nest_asyncio出现错误
    sanic 相关的插件
    linux如何配置nginx全局变量
  • 原文地址:https://www.cnblogs.com/orchid/p/3328887.html
Copyright © 2011-2022 走看看