zoukankan      html  css  js  c++  java
  • 连续数的和

    题面描述

    对于一个给定的正整数 n ,请你找出一共有多少种方式使 n 表示为若干个连续正整数的和,要求至少包括两个正整数。如 n=15 时,可以有 3 种方式:( 1+2+3+4+5 ),( 4+5+6 ),( 7+8 )。

    输入数据

    输入数据第一行为一个正整数 T ,表示测试数据的组数。 随后的 T 行中,每行包括一组测试数据,为一个整数 n(1≤T≤1000,n≤10^9)。

    输出数据

    对每一组输入数据,输出一行结果 ”Case #id: M” ,表示第 id 组数据的结果是 M , id 从 1 开始。

    样例输入

    2
    3
    15

    样例输出

    Case #1: 1
    Case #2: 3

    方法一:

      思路:对于一个给定的数n,例如22,设置两个指针 i,j     则所求为 sum(i,j) = i+(i+1)+(i+2)+...j =n   其每一个数必定小于等于n/2 +1 ,若非如此,无论怎么加都会超过原来的数。   那么就可以循环判断 sum(i,j) 与 n 的关系:

    当 sum(i,j) ==n 时,得到一个个结果。

    当 sum (i, j) < n 时,说明还不够,j往后一位变成j+1,此时sum = sum + j +1。

    当 sum(i,j) > n时,说明过了,此时i往后移一位,变成i+1。此时 sum = sum -i。

    直到 i >= j 或者 j > n/2+1。       

     1 #include<iostream>
     2 
     3 using namespace std;
     4 
     5 
     6 int function(int n)
     7 {
     8     int mid = n / 2 + 1;
     9     int i = 1;
    10     int j = i + 1;
    11     int sum = i + j;
    12     int count = 0;
    13 
    14     while (i < j && j <= mid)    
    15     {
    16         if (sum == n)
    17         {
    18             count++;
    19             sum -= i;
    20             i++;
    21         }
    22         else if (sum < n)
    23         {
    24             j++;
    25             sum += j;
    26         }
    27         else if (sum > n)
    28         {
    29             sum -= i;
    30             i++;
    31         }
    32     }
    33     return count;
    34 }
    35 
    36 int main()
    37 {
    38     int i, n;
    39     cin >> n;
    40     int *a = new int[n + 1];
    41 
    42     for (i = 1; i <= n; ++i)
    43     {
    44         cin >> a[i];
    45     }
    46 
    47     for (i = 1; i <= n; ++i)
    48     {
    49         cout << "Case #" << i << ": " << function(a[i]) << endl;
    50     }
    51 
    52     return 0;
    53 
    54 }

      此程序效率极低。。。提交后超出时间限制。。。

    方法二:

    利用等差数列

    an = a1+(n-1)d    这里公差d = 1

    所以 an = a1+n-1

    Sn = (a1+an)n/2 = (2a1+n-1)n/2

    我们输入的数就是Sn  ,我们要找的是以a1开始递增的数列使其和为Sn

    这里我们可以用循环来判定,给定一个n,Sn已知,就可以求出a,如果a为正整数那么就可以找到等差数列的首项,加上n给定,d=1,那么就可以写出这个和式子。

    注意,这里的n无须一直从2开始枚举下去,可以由Sn = (a1+an)n/2 = (2a1+n-1)n/2,所以a1=Sn/n-n/2+1/2,该式子为递减函数,n越大,a越小,而a最小为1,故另a=1时可确定n的最大范围。

    令a=1,得二元一次方程(1/2+n/2)*n=S,即n^2+n-2*S=0,可得方程两个根中取较大的根n=0.5*(-1+sqrt(1+8*S)),从而确定n的最大枚举范围。

    #include<iostream>
    #include<math.h>
    using namespace std;
    
    
    int function(int n)
    {
        int count = 0;       // count用来保存最后的结果
        double a1;
        int N = (int)(0.5*(-1 + sqrt(1 + 8 * n)));
        for (int cnt = 2; cnt <= N; ++cnt) {            从2开始枚举 
            a1 = 1.0*n / cnt - cnt / 2.0 + 1 / 2.0;
            if ((int)a1 == a1 && a1 > 0) {     //  如果得到的a1为整数且a1大于0 ,那么就符合预期
                count++;   //  每有一组符合,就加1
            }
        }
        return count;
    }
    
    int main()
    {
        int i, n;
        cin >> n;
        int *a = new int[n + 1];
    
        for (i = 1; i <= n; ++i)
        {
            cin >> a[i];
        }
    
        for (i = 1; i <= n; ++i)
        {
            cout << "Case #" << i << ": " << function(a[i]) << endl;
        }
        system("pause");
        return 0;
    
    }
  • 相关阅读:
    Leetcode 35. 搜索插入位置 二分查找
    《算法竞赛进阶指南》 第一章 Acwing 91. 最短Hamilton路径
    《算法竞赛进阶指南》 第一章 Acwing 90. 64位整数乘法
    《算法竞赛进阶指南》 第一章 Acwing 89. a^b 位运算 更新bitset版本
    挑战程序设计竞赛 2章习题 Aizu
    挑战程序设计竞赛 2章习题 poj 2718 Smallest Difference dfs
    Leetcode 33. 搜索旋转排序数组 二分
    Leetcode 30. 串联所有单词的子串
    LeetCode 22. 括号生成 DFS
    Leetcode 16. 最接近的三数之和 及后继几题
  • 原文地址:https://www.cnblogs.com/ll-10/p/9351630.html
Copyright © 2011-2022 走看看