BZOJ 2226 - [Spoj 5971] LCMSum
Published on 2017-01-20描述
给定 ,请你求:
有 组询问。
分析
通常 需要化为 :
枚举 为 ,化简一番:
设 为内层和式的值,则考虑快速求 :
我们考虑对于 ,如果有 ,必然有 (根据欧几里得算法),所以 中与 互质的数必然是成对出现的,那么 就可求出:
至此可以 预处理出 ,枚举 的约数来 回答单组询问。但是时间仍然难以承受。
这种题中,降低时间复杂度的方法无非就是预处理,我们考虑答案的形式:
由于 时需要特判,很烦人,我们单独考虑,由于 ,缺一个 ,补上即可,那么式子化简为:
设 ,那么我们就可以用欧拉筛来 的预处理出所有的 ,这样就可以 的回答询问了。
我们注意到 是有积性的,原因是 有积性,而对于一个积性函数 来说:
也是积性的,所以 是有积性的,于是可以线筛 预处理出所有的 (代码里面写的是欧拉筛)。
代码
// Created by Sengxian on 2017/01/19. // Copyright (c) 2017年 Sengxian. All rights reserved. // BZOJ 2226 欧拉筛 #include <bits/stdc++.h> using namespace std; typedef long long ll; inline int readInt() { static int n, ch; n = 0, ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) n = n * 10 + ch - '0', ch = getchar(); return n; } const int MAX_N = 1000000 + 3; int primes[MAX_N], cnt = 0; bool isPrime[MAX_N]; int phi[MAX_N]; ll f[MAX_N]; void prepare() { fill(isPrime + 2, isPrime + MAX_N, true); phi[1] = 1; for (int i = 2; i < MAX_N; ++i) { if (isPrime[i]) primes[cnt++] = i, phi[i] = i - 1; for (int j = 0; j < cnt && primes[j] * i < MAX_N; ++j) { int t = primes[j] * i; isPrime[t] = false; if (i % primes[j] == 0) { phi[t] = phi[i] * primes[j]; break; } else { phi[t] = phi[i] * (primes[j] - 1); } } } for (int i = 1; i < MAX_N; ++i) for (int j = i; j < MAX_N; j += i) f[j] += (ll)phi[i] * i; } inline ll solve(int n) { if (n == 1) return 1; else if (n == 2) return 4; ll res = f[n] + 1; return res * n / 2; } int main() { prepare(); int caseNum = readInt(); while (caseNum--) printf("%lld\n", solve(readInt())); return 0; }