给出T组n,
求 ∑i<ni=1∑nj=i+1gcd(i,j)
1<=n<=5000000,1<=T<=50000
51 nod没良心,本来O(n log n)可以过的,可是不知为什么现在跑得这么慢,我把老曹的标再交了一次也T了3个点,于是强行推了O(n)的做法。
先转换为:
∑ji=1∑i−1j=1gcd(i,j)
=∑ji=1∑ij=1gcd(i,j)−∑ni=1gcd(i,i)
∑ji=1∑ij=1gcd(i,j)
=∑ni=1φ(i)∗⌊n/i⌋∗(⌊n/i⌋+1)/2
线筛出φ,然后分块。
时间复杂度:
O(T n√ )
T了#17 - 25.
设 f(i)=∑i−1j=1gcd(i,j)
如果我们能够快速求出f(i),求一个前缀和,就可以O(1)求解。
我们可以想到枚举gcd.
伪代码:
i = 1 to n
j = 2 to n / i
f(i * j) += φ(j) * i
时间复杂度:O(n log n)
其实f(i)可以直接线筛:
f(i)=∑i−1j=1gcd(i,j)
先看作:
∑ij=1gcd(i,j)
之后再减回去。
=∑d|id∗φ(i/d)
这显然就是个狄利克雷卷积,所以f(i)是一个积性函数。
接着我们考虑i=p^q的时候怎么求 f(pq) 。
f(pq)
=∑qk=0pk∗φ(pq−k)
=(∑q−1k=0pk∗(pq−k−pq−k−1))+pq
=(∑q−1k=0pq−pq−1)+pq
=q∗(pq−pq−1)+pq
所以在线筛的时候还需要记录最小质因子的指数和最小质因子的幂。
方法三Code:
#include
#define N 5000000
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
long long f[N + 5];
int n, T, x[N + 5], y[N + 5], p[348514];
bool bz[N + 5];
int main() {
f[1] = 1;
fo(i, 2, N) {
if(!bz[i]) p[++ p[0]] = i, x[i] = 1, y[i] = i, f[i] = 2 * i - 1;
fo(j, 1, p[0]) {
int k = i * p[j]; if(k > N) break;
bz[k] = 1;
if(!(i % p[j])) {
x[k] = x[i] + 1;
y[k] = y[i] * p[j];
f[k] = f[k / y[k]] * (x[k] * (y[k] - y[k] / p[j]) + y[k]);
break;
}
x[k] = 1;
y[k] = p[j];
f[k] = f[i] * f[p[j]];
}
}
fo(i, 1, N) f[i] = f[i - 1] + f[i] - i;
for(scanf("%d", &T); T; T --)
scanf("%d", &n), printf("%lld\n", f[n]);
}
方法2Code:
#include
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int Maxn = 5000000;
long long ans[Maxn + 5];
int n, T, p[400000], phi[Maxn + 5];
bool bz[Maxn + 5];
int main() {
phi[1] = 1;
fo(i, 2, Maxn) {
if(!bz[i]) p[++ p[0]] = i, phi[i] = i - 1;
fo(j, 1, p[0]) {
int k = i * p[j]; if(k > Maxn) break;
bz[k] = 1;
if(!(i % p[j])) {
phi[k] = phi[i] * p[j];
break;
}
phi[k] = phi[i] * (p[j] - 1);
}
}
fo(i, 1, Maxn) fo(j, 2, Maxn / i) ans[i * j] += i * phi[j];
fo(i, 2, Maxn) ans[i] = ans[i - 1] + ans[i];
printf("%d\n", ans[9]);
for(scanf("%d", &T); T; T --)
scanf("%d", &n), printf("%lld\n", ans[n]);
}
方法1Code:
#include
#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const ll Maxn = 5000000;
int n, T, p[400000];
ll phi[Maxn + 5];
bool bz[Maxn + 5];
int main() {
phi[1] = 1;
fo(i, 2, Maxn) {
if(!bz[i]) p[++ p[0]] = i, phi[i] = i - 1;
fo(j, 1, p[0]) {
int k = i * p[j];
if(k > Maxn) break;
bz[k] = 1;
if(i % p[j] == 0) {
phi[k] = phi[i] * p[j];
break;
}
phi[k] = phi[i] * (p[j] - 1);
}
}
fo(i, 1, Maxn) phi[i] = phi[i - 1] + phi[i];
for(scanf("%d", &T); T; T --) {
ll ans = 0;
scanf("%d", &n);
fo(i, 1, n) {
int j = n / (n / i);
ans += (phi[j] - phi[i - 1]) * (n / i) * (n / i + 1) / 2;
i = j;
}
ans -= (ll) n * (n + 1) / 2;
printf("%lld\n", ans);
}
}