You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
2.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_05_1_week;
// 来自学员问题,蓝桥杯练习题
// 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)的方法,
public class Code04_SumOfQuadraticSum {
// 暴力方法
public static long sum1(long n) {
int[] cnt = new int[(int) n + 1];
for (int num = 1; num <= n; num++) {
for (int j = 1; j <= num; j++) {
if (num % j == 0) {
cnt[j]++;
}
}
}
long ans = 0;
for (long i = 1; i <= n; i++) {
ans += i * i * (long) (cnt[(int) i]);
}
return ans;
}
// 正式方法
// 时间复杂度O(开平方根N + 开平方根N * logN)
public static long sum2(long n) {
// 100 -> 10
// 200 -> 14
long sqrt = (long) Math.pow((double) n, 0.5);
long ans = 0;
for (long i = 1; i <= sqrt; i++) {
ans += i * i * (n / i);
}
// 后半段
// 给你一个个数,二分出几个因子,处在这个个数上!
// 由最大个数(根号N), 开始二分
for (long k = n / (sqrt + 1); k >= 1; k--) {
ans += sumOfLimitNumber(n, k);
}
return ans;
}
// 平方和公式n(n+1)(2n+1)/6
public static long sumOfLimitNumber(long v, long n) {
long r = cover(v, n);
long l = cover(v, n + 1);
return ((r * (r + 1) * ((r << 1) + 1)
- l * (l + 1) * ((l << 1) + 1)) * n)
/ 6;
}
public static long cover(long v, long n) {
long l = 1;
long r = v;
long m = 0;
long ans = 0;
while (l <= r) {
m = (l + r) / 2;
if (m * n <= v) {
ans = m;
l = m + 1;
} else {
r = m - 1;
}
}
return ans;
}
// 实验
// 解法来自观察
// 打表(暴力)
// f(1) + ... + f(n)
public static void test(int n) {
int[] cnt = new int[n + 1];
for (int num = 1; num <= n; num++) {
for (int j = 1; j <= num; j++) {
if (num % j == 0) {
cnt[j]++;
}
}
}
for (int i = 1; i <= n; i++) {
System.out.println("因子 : " + i + ", 个数 : " + cnt[i]);
}
}
public static void main(String[] args) {
// test(100);
System.out.println("测试开始");
for (long i = 1; i < 1000; i++) {
if (sum1(i) != sum2(i)) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
long n = 50000000000L; // 5 * 10的10次方
long start = System.currentTimeMillis();
sum2(n);
long end = System.currentTimeMillis();
System.out.println("大样本测试n = " + n);
System.out.println("运行时间 : " + (end - start) + " ms");
}
}