51Nod 1188 - 最大公约数之和 V2(欧拉函数)
题目链接 https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1188
【题目描述】
给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和。相当于求
Input
第1行:1个数T,表示后面用作输入测试的数的数量。(1 <= T <= 50000)
第2 - T + 1行:每行一个数N。(2 <= N <= 5000000)
Output
共T行,输出最大公约数之和。
Input示例
3
10
100
200000
Output示例
67
13015
143295493160
【思路】
51Nod 1040是这题的简化版,求的是
有公式
把它用到这道题里面去
按照这个式子去计算,当然不能直接像这样直接枚举每个 ,然后再枚举每个 的因子 ,通过观察可以发现这个式子枚举的是 所有数除了自己之外的所有因子,所以换个角度出发,直接枚举每个因子 ,然后把 的若干倍作为 来使用,就可以像埃氏筛那样在 的时间内预处理所有答案了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5000005;
int phi[maxn];
ll ans[maxn];
void phi_table(int n) {
for (int i = 2; i <= n; ++i) phi[i] = 0;
phi[1] = 1;
for (int i = 2; i <= n; ++i) {
if (0 == phi[i]) {
for (int j = i; j <= n; j += i) {
if (0 == phi[j]) phi[j] = j;
phi[j] = phi[j] / i * (i - 1);
}
}
}
for(int i=1;i<=n;++i){
for(int j=2;j*i<=n;++j){
ans[i*j]+=(ll)phi[j]*(ll)i;
}
}
for(int i=1;i<=n;++i) ans[i]+=ans[i-1];
}
int main(){
phi_table(maxn-1);
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
printf("%lld\n",ans[n]);
}
return 0;
}