小米OJ 有多少个公差为 2 的等差数列【思维】

序号:#31
难度:有挑战
时间限制:1000ms
内存限制:10M

描述

给出一个正整数N(2<= N <=10000000),统计有多少公差为2的正整数等差数列,使得数列的和为N。

举例: 正整数 15,可以写为 15 和 3,5,7 两个等差数列。 其中 15 自身就是一个等差数列,3+5+7=15 也是一个符合条件的等差数列,所以输出为 2,表示有两个符合条件的等差数列。

请注意时间复杂度限制

输入

一个正整数,表示等差数列中所有数的和,范围为 [2, 10000000]

输出

一个正整数,表示可以找到多少符合条件的正整数等差数列。 (由于一个数字也可以算做等差数列,所以输出至少为1)

输入样例

15
30
50

输出样例

2
4
3

分析:
本题还不错,本来自己想了一种方法,看了下别人的代码,发现另一种解法,挺好。
两个思路,都是√n的复杂度

  1. 反向枚举
    我们知道等差数列求和的的性质: 大概是 => “梯形面积的求法” = (上低 + 下低) * 高 / 2
    对于一个等差数列形如 : a i , a i + 1 , . . . . , a j {a_i, a_{i + 1}, .... ,a_j} ai,ai+1,....,aj

    ∑ a i a j = S = ( a i + a j ) ∗ ( j − i + 1 )   /   2 ,    i < j < n \sum_{a_i}^{a_j} = S = (a_i + a_j) * (j - i + 1) ~/~ 2,~~ i <j<n aiaj=S=(ai+aj)(ji+1) / 2,  i<j<n

    化简下为: 2 ∗ S = ( a i + a j ) ∗ ( j − i + 1 ) 2 * S = (a_i + a_j) * (j - i + 1) 2S=(ai+aj)(ji+1)
    所以我们只需将 2 * S进行分解即可,这里的S为题目中的n
    这里也假设:
    p = ( a i + a j ) , q = ( j − i + 1 ) p = (a_i + a_j) , q = (j - i + 1) p=(ai+aj)q=(ji+1)
    这里我们注意到 p 只能为偶数
    我们可以得到一个二元原方程组为:

    a i + a j = p a_i + a_j = p ai+aj=p
    a j − a i = ( q − 1 ) ∗ 2 a_j - a_i = (q - 1) * 2 ajai=(q1)2

    解方程组可得 a j = p / 2 + ( q − 1 ) a_j = p / 2 + (q - 1) aj=p/2+(q1)
    又因为 a i > 0 , 只 需 要 满 足 a j 存 在 即 可 a_i > 0 , 只需要满足a_j 存在即可 ai>0,aj,即: p > a j = p / 2 + ( q − 1 ) p > a_j = p / 2 + (q - 1) p>aj=p/2+(q1),
    即: p / 2 > q − 1 p / 2 > q - 1 p/2>q1
    总之只需满足
    ( 1 )    p / 2 > q − 1 (1) ~~ p / 2 > q - 1 (1)  p/2>q1
    ( 2 )    p % 2 = = 0 (2) ~~p \% 2 == 0 (2)  p%2==0
    复杂度为 O ( n ) O(\sqrt n) O(n )

  2. 正向构造:
    我们考虑n在[1,√n]内的所有因子,答案就是因子的个数
    比如n = 30的时候
    30 = 1 * 30 -> {30}
    30 = 2 * 15 -> {14,16}
    30 = 3 * 10 -> {8,10,12}
    30 = 5 * 6 -> {2,4,6,8,10}

    假设 n = p * q
    可以发现, 我们可以这样理解,
    p 代表集合的大小,
    q 代表集合中的平均数,可以保证肯定存在这样一个集合

    所以我们只需要枚举所有的因子即可,复杂度为 O ( n ) O(\sqrt n) O(n )
    第二种解法的确没想到,直接枚举即可。

参考代码

#include

/*
	第二种解法很简单,就不写了~~
*/

using namespace std;
int main(){
	int n;
	while (cin >> n) {
        int cnt = 0;
        n *= 2;
        int m = (int) sqrt(n + 0.5);
        for (int i = 1; i <= m; i++) {
            if (n % i == 0) {
                int p = i, q = n / i;
                if (q & 1) continue;
                if (q / 2 > p - 1) cnt++;
            }
        }
        cout << cnt << endl;
	}
    return 0;
}

你可能感兴趣的:(----,经典思维题,----)