题目描述
题目大意:问你1到n中的数和n的lcm之和,T组询问。T <= 300000,n <= 1000000。
思路
一看就是比较套路的题。随便化简一下,大概是这样
∑i=1n[n,i]=∑i=1nni(n,i)=n∑i=1n∑d=1n[(i,n)=d]id
然后先枚举
d
(只能是
n∑d|n∑i=1nd[(i,nd)=1]i
接下来还要不要 反演呢?其实到这里已经大功告成了。根据我不知道从哪里偷来的公式 ∑ni=1[(i,n)=1]i=φ(n)∗n+[n=1]2 ,答案就是
n∑d|nφ(d)∗d+[d=1]2
至于这个公式怎么证?显然。(证它干嘛呢)
于是总时间就变成了 O(n+Tn√) ,理论跑不过,但政治书上说,理论要联系实际。
代码
#include <bits/stdc++.h>
#define maxn 1000100
#define temp (i * prime[j])
using namespace std;
typedef long long LL;
int n, T, cnt;
int prime[maxn], phi[maxn];
bool Vis[maxn];
LL ans;
void Da(){
phi[1] = 1;
for(int i = 2; i < maxn; i++){
if(!Vis[i]){
prime[++cnt] = i;
phi[i] = i - 1;
}
for(int j = 1; j <= cnt && temp < maxn; j++){
Vis[temp] = true;
if(i % prime[j] == 0){
phi[temp] = phi[i] * prime[j];
break;
}
else phi[temp] = phi[i] * (prime[j] - 1);
}
}
}
int main(){
scanf("%d", &T);
Da();
while(T --){
scanf("%d", &n);
ans = 0LL;
for(int i = 1; i * i <= n; i++)
if(n % i == 0){
ans += (1LL * phi[i] * i + ((i == 1) ? 1 : 0)) >> 1LL;
if(n / i != i) ans += (1LL * phi[n/i] * (n/i)) >> 1LL;
}
printf("%lld\n", n * ans);
}
return 0;
}
明敕星驰封宝剑,辞君一夜取楼兰。