写完这题,就可以去写 Light OJ 1375了
题意:
求
∑i=1i=n LCM(i,n)
1≤T≤300000 1≤n≤106
思路:
LCM(i,n)=i∗ngcd(i,n)
令 g=gcd(i,n) , 得到:
lcm(i,n)=ig∗ng∗g
我们可以枚举 g=gcd(i,n) 的值,显然这个值一定是 n 的约数,那么现在开始算n∗ig ,对于这个 g 值下进行求和,又因为i 满足条件 g=gcd(i,n) , 所以明显所有的 ig 与 ng 互质,然后进行求和的时候就可以用到一个结论:
对于 2≤n , 不大于 n 且与n 互质的整数的和为 n∗phi(n)2 ,那么我们要求的和值就是等于 n∗n/g∗phi(n/g)2 , 所以ans=n+n∗∑d|n,d!=n n/d∗phi(n/d)2=n+n∗∑d|n,d!=1 d∗phi(d)2
注意,这里要特殊处理一下 g=n 哦!
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int N = 5 + 1e6, MOD = 7+1e9;
LL ans[N], phi[N];
bool flag[N];
int prime[N/3];
int p[10000];
void init()
{
int i, j, k;
k = 0;
for(i = 2;i < N;++ i) {
if(!flag[i]) {
prime[k++] = i;
phi[i] = i-1;
}
for(j = 0;j < k && i * prime[j] < N;++ j){
flag[i * prime[j]] = true;
if(i % prime[j] == 0) {
phi[i*prime[j]] = phi[i] * prime[j];
break;
}
else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
for (int i = 1; i < N ; ++ i) {
for(int j = i;j < N;j += i) {
ans[j] += 1LL* i * phi[i] /2;
}
}
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T --) {
int n;
scanf("%d",&n);
printf("%lld\n",(ans[n] + 1) * n);
}
return 0;
}