bzoj2226[Spoj 5971] LCMSum

题目大意:给定T(10^5)组数据,每次给出n(10^6),求lcm(i,n){1<=i<=n}的和

一眼看上去就是一道数学题……蒟蒻数学太差思路略微诡异……我想着能不能nlogn直接把所有答案算出来,然后yy了一下……

设F[n]为所求的值,f[n]为小于n的质数的和,我们考虑到lcm(a,b)=ab/gcd(a,b),那么我们可以去枚举gcd,对于一个n的因数d,在1到n中和n最大公因数为d的数对于F[n]的贡献就显而易见了,即F[n]+=n*d*f[n/d],这样可以nlogn求出

对于f[n]求法也非常的简单,可以看出f[n]=sigma(i*[gcd(i,n)=1]),再把[gcd(i,n)=1]写成莫比乌斯函数的形式,套路一样的重新组合啊什么的,最终就是可以变成这样的形式:f[n]+=u[k]*(k*((n/k)+1)(n/k)/2){k|n},也是可以在nlogn时间求出。

听说有根号大法……不过不会……数学太弱QAQ

为了避免常数被卡特意用C++写的

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #define ll long long
 6 using namespace std;
 7 const int N=1000086;
 8 ll f[N],F[N],pri[N],vis[N],mu[N],tot;
 9 int read()
10 {
11     int x=0,f=1;char ch=getchar();
12     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 void getmu()
17 {
18     mu[1]=1;tot=0;
19     for(int i=2;i<=N;i++)
20     {
21         if(!vis[i]){pri[++tot]=i;mu[i]=-1;}
22         for(int j=1;j<=tot&&pri[j]*i<=N;j++)
23         {
24             vis[i*pri[j]]=1;
25             if(i%pri[j]==0){mu[pri[j]*i]=0;break;}
26             else mu[pri[j]*i]=-mu[i];
27         }
28     }
29 }
30 void getf()
31 {
32 
33     for(int i=1;i<=N;i++)
34         for(int j=1;j*i<=N;j++)
35             f[i*j]+=mu[i]*((ll)i*(j+1)*j/2);
36 }
37 void getF()
38 {
39     for(int i=1;i<=N;i++)
40         for(int j=1;j*i<=N;j++)
41             F[i*j]+=f[j]*i*j;
42 }
43 int main()
44 {
45     getmu();getf();getF();
46     int T=read();
47     while(T--)
48     {
49         int n=read();printf("%lld\n",F[n]);
50     }
51     return 0;
52 }

 

posted @ 2017-01-15 23:47  OldJang  阅读(403)  评论(0编辑  收藏  举报