前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2022-07-19:f(i) : i的所有因子,每个因子都平方之后,累加起来。 比如f(10) = 1平方 + 2平方 + 5平方 + 10平方 = 1 +

2022-07-19:f(i) : i的所有因子,每个因子都平方之后,累加起来。 比如f(10) = 1平方 + 2平方 + 5平方 + 10平方 = 1 +

原创
作者头像
福大大架构师每日一题
发布2022-07-19 22:52:19
5610
发布2022-07-19 22:52:19
举报

2022-07-19:f(i) : i的所有因子,每个因子都平方之后,累加起来。

比如f(10) = 1平方 + 2平方 + 5平方 + 10平方 = 1 + 4 + 25 + 100 = 130。

给定一个数n,求f(1) + f(2) + .. + f(n)。

n <= 10的9次方。

O(n)的方法都会超时!低于它的!

O(根号N)的方法,就过了,一个思路。

O(log N)的方法,

来自蓝桥杯练习题。

答案2022-07-19:

观察表,二分法。

时间复杂度O(开平方根N + 开平方根N * logN)。

代码用rust编写。代码如下:

代码语言:rust
复制
fn main() {
    println!("测试开始");
    for i in 1..1000 {
        if sum1(i) != sum2(i) {
            println!("出错了{}", i);
        }
    }
    println!("测试结束");
}

// 暴力方法
fn sum1(n: i64) -> i64 {
    let mut cnt: Vec<i64> = vec![];
    for _ in 0..n + 1 {
        cnt.push(0);
    }
    for num in 1..=n {
        for j in 1..=num {
            if num % j == 0 {
                cnt[j as usize] += 1;
            }
        }
    }
    let mut ans = 0;
    for i in 1..=n {
        ans += i * i * cnt[i as usize];
    }
    return ans;
}

fn get_sqrt(n: i64) -> i64 {
    let mut l: i64 = 1;
    let mut r = n;
    let mut m: i64;
    let mut mm: i64;
    let mut ans = 1;
    while l <= r {
        m = l + ((r - l) >> 1);
        mm = m * m;
        if mm == n {
            return m;
        } else if mm < n {
            ans = m;
            l = m + 1;
        } else {
            r = m - 1;
        }
    }
    return ans;
}

// 正式方法
// 时间复杂度O(开平方根N + 开平方根N * logN)
fn sum2(n: i64) -> i64 {
    // 100 -> 10
    // 200 -> 14
    let sqrt = get_sqrt(n);
    let mut ans = 0;
    for i in 1..=sqrt {
        ans += i * i * (n / i);
    }
    // 后半段
    // 给你一个个数,二分出几个因子,处在这个个数上!
    // 由最大个数(根号N), 开始二分
    let mut k = n / (sqrt + 1);
    while k >= 1 {
        ans += sum_of_limit_number(n, k);
        k -= 1;
    }
    return ans;
}

// 平方和公式n(n+1)(2n+1)/6
fn sum_of_limit_number(v: i64, n: i64) -> i64 {
    let r = cover(v, n);
    let l = cover(v, n + 1);
    return ((r * (r + 1) * ((r << 1) + 1) - l * (l + 1) * ((l << 1) + 1)) * n) / 6;
}

fn cover(v: i64, n: i64) -> i64 {
    let mut l = 1;
    let mut r = v;
    let mut m;
    let mut ans = 0;
    while l <= r {
        m = (l + r) / 2;
        if m * n <= v {
            ans = m;
            l = m + 1;
        } else {
            r = m - 1;
        }
    }
    return ans;
}

执行结果如下:

在这里插入图片描述
在这里插入图片描述

左神java代码

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档