Problem code: LCMSUM |
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
题意:sigma(lcm(i,n)) ; 1<=i<=n
思路:题意倒是很简单,有类似的题目sigma(gcd(i,n)) ;1<=i<=n;
一看就是果然是同类型的。
gcd(i,n)的题目 http://www.cnblogs.com/tom987690183/p/3247439.html
这个是求lcm()最小公倍数.
同样的思路,我们枚举gcd() = d 则在[ 1 , n ]中与n最大公约数为d的值有euler(n/d)个.
这些数的和为euler(n/d)*n/2; 我们知道lcm = x*n/(gcd(x,n)) = > x*n/d ;
因为与n gcd() = d的数字为x1,x2,x3....
根据lcm = x*n/(gcd(x,n)) 可以得到 (n/d)*(x1+x2+x3...) => [euler(n/d)*n/2]*(n*d);
这里需要注意的是当gcd(i,n) = n的时候,用euler(n)*n/2算的时候是不对的,就特判吧。
这样的思路,我们就可以试一下打欧拉表opl[ ],需要时间o(N);
然后对于n,要用sqrt(n)的时间。
T*sqrt(n)+o(N) = 3^8+10^6.果断超时。以为能ac,吼吼。
1 #include<iostream> 2 #include<stdio.h> 3 #include<cstring> 4 #include<cstdlib> 5 using namespace std; 6 typedef long long LL; 7 8 const int maxn = 1e6+3; 9 int opl[maxn]; 10 void init() 11 { 12 for(int i=1;i<maxn;i++) opl[i] = i; 13 for(int i=2;i<maxn;i++) 14 { 15 if(opl[i]==i) opl[i] = i-1; 16 else continue; 17 for(int j=i+i;j<maxn;j=j+i) 18 opl[j] = opl[j]/i*(i-1); 19 } 20 } 21 int main() 22 { 23 int T; 24 LL n; 25 init(); 26 scanf("%d",&T); 27 while(T--) 28 { 29 scanf("%lld",&n); 30 LL sum = 0; 31 for(LL i=1;i*i<=n;i++) 32 { 33 if(n%i==0) 34 { 35 if(i!=n) 36 sum = sum + (n/i)*(opl[n/i]*n/2); 37 LL tmp = n/i; 38 if(tmp!=i && tmp!=n) 39 sum = sum + i*(opl[i]*n/2); 40 } 41 } 42 printf("%lld\n",sum+n); 43 } 44 return 0; 45 }
这样的话,是不行了。
原始相当于
也就能转化为(easy)
这样的话,我们就能单独的求出euler(a)*a/2;然后用它来筛选g[n]的值。
(x|n的意思代表 n是x的倍数)
我们想到在第一种方法里,我们用sqrt(n)来求它的因子的方法。
同理,逆向一下就好。
这样我们只需要o(N) 的时间对g[]进行筛选。总的预处理时间
3*o(N) = > 3*10^6;
完毕。
需要注意的是,我们没有把gcd() = n的情况包含进去,所以最后要+n。
代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<cstring> 4 #include<cstdlib> 5 using namespace std; 6 typedef long long LL; 7 8 const int maxn = 1e6+3; 9 LL opl[maxn]; 10 LL g[maxn]; 11 void init() 12 { 13 for(int i=1;i<maxn;i++) opl[i] = i; 14 //这种方法筛选素数,不用和以前一样要先刷素数,还开num[]; 15 for(int i=2;i<maxn;i++) 16 { 17 if(opl[i]==i) 18 opl[i] = i-1; 19 else continue; 20 for(int j=i+i;j<maxn;j=j+i) 21 opl[j] = opl[j]/i*(i-1); 22 } 23 for(int i=2;i<maxn;i++){ 24 opl[i] = opl[i]*i/2; 25 g[i] = opl[i]; 26 } 27 for(long long i=2;i<=1000;i++) //这里的i 不能用int,肯定会超int的 28 { 29 for(long long j=i*i,k=i;j<maxn;j=j+i,k++) 30 if(i!=k) //不重复 31 g[j] = g[j] + opl[i]+opl[k]; 32 else g[j] = g[j] + opl[i]; 33 } 34 } 35 int main() 36 { 37 init(); 38 int T; 39 LL n; 40 scanf("%d",&T); 41 while(T--) 42 { 43 scanf("%lld",&n); 44 printf("%lld\n",g[n]*n+n); 45 } 46 return 0; 47 }