SPOJ (BNUOJ) LCM Sum
LCM Sum
Time Limit: 5000 ms Case Time Limit: 5000 ms Memory Limit: 262144 KB
Submit: 4 Accepted: 0
Description
Given n, calculate the sum LCM(1,n) + LCM(2,n) + .. + LCM(n,n), where LCM(i,n) denotes the Least Common Multiple of the integers i and n.
Input
The first line contains T the number of test cases. Each of the next T lines contain an integer n.
Output
Output T lines, one for each test case, containing the required sum.
Example
Sample Input :
3
1
2
5
Sample Output :
1
4
55
Constraints
1 <= T <= 300000
1 <= n <= 1000000
Input
Output
Sample Input
Sample Output
Source
own problem used for Codechef Snackdown Onsite
卡时卡的好紧
//思路 欧拉函数
gcd(i,n)=k 求出所有的这样i的和 n*(phi[n/k]*(n/k)/2)*k
lcm(i,n)=i*n/k; 所以 所有这样的i sigma(lcm(i,n))=n*[n*(phi[n/k]*(n/k)/2)8k]/k
整理得 n*n*phi[n/k]/2/k 然后sqrt(n) 时间复杂度是 预处理欧拉函数时间+Qsqrt(N),这个超时、、、
然后再整理,(i|n) sigma(lcm(i,n))=n*(n/k)*phi[n/k]/2; 把n/k 看成a 则 =n*a*phi[a]/2
这样就可以预处理所有的 lcm(i,N) 1<=i<=N 值, 输出直接是O(1);
//
超时代码
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 1000001
int phi[N];
#define __int64 long long
void set()//求欧拉函数
{
int i,j;
for(i=2;i<N;i++)
if(i%2)
phi[i]=i;
else
phi[i]=i/2;
for(i=3;i<N;i+=2)
if(phi[i]==i)
for(j=i;j<N;j+=i)
phi[j]=phi[j]/i*(i-1);
}
int main()
{
set();
int T;
int m;
__int64 n;
__int64 sum;
scanf("%d",&T);
int i;
while(T--)
{
scanf("%lld",&n);
if(n==1) { printf("1\n");continue; }
m=sqrt((double)n);
sum=n*n*phi[n]/2;
for(i=2;i<=m;i++)
if(n%i==0)
{
sum+=n*n*phi[n/i]/2/i;
if(i*i<n)
{
sum+=n*n*phi[i]/2/(n/i);
}
}
sum+=n;
printf("%lld\n",sum);
}
return 0;
}
AC 代码
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <algorithm> using namespace std; #define N 1000001 #define __int64 long long __int64 phi[N]; __int64 ans[N]; void set() { __int64 i,j; for(i=2;i<N;i++) if(i%2) phi[i]=i; else phi[i]=i/2; for(i=3;i<N;i+=2) if(phi[i]==i) for(j=i;j<N;j+=i) phi[j]=phi[j]/i*(i-1); ans[1]=1; for(i=2;i<N;i++) ans[i]=i*phi[i]/2+1; __int64 k;//开始变量定义成int 计算过程中导致超过 int范围 for(i=2;i<=1000;i++) { ans[i*i]+=i*phi[i]/2; for(j=i*i+i,k=i+1;j<N;j+=i,k++) ans[j]+=i*phi[i]/2+k*phi[k]/2; } } int main() { set(); int T; int n; scanf("%d",&T); while(T--) { scanf("%d",&n); printf("%lld\n",ans[n]*n); } return 0; }