BZOJ[SPOJ5971]LCMSum

Posted G . H . O . S . T . R . E . A

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ[SPOJ5971]LCMSum相关的知识,希望对你有一定的参考价值。

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.

Sample Input

3
1
2
5

Sample Output

1
4
55

HINT

1 <= T <= 300000
1 <= n <= 1000000

 

题解:

题意即求∑LCM(i,n)(1<=i<=n)。

枚举gcd,统计对答案的贡献。

原本我采用的方法是容斥,求出n的因数表后,由大到小枚举gcd[i],并把更小的gcd[j]的贡献减去相应的值。

复杂度还可以,但是常数非常大,在BZ上过不了。

有一个常数更小的方法:枚举gcd后,我们需要知道1~n div gcd-1中所有与n div gcd互质的数的和。

设m=n div gcd。若x与m互质,则m-x与m互质,即与m互质的数成对出现,所以与m互质的数的和为m*φ(m)div 2。(m<=2时依旧成立)

线性筛预处理出欧拉函数,就可以快速求值了。

 

代码:

TLE的容斥(P++注意):

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define begin {
 4 #define end }
 5 #define while while(
 6 #define if if(
 7 #define do )
 8 #define then )
 9 #define for for(
10 #define fillchar(a,b,c) memset(a,c,b)
11 #define writeln printf("\\n")
12 #define write printf
13 #define readln readl()
14 #define inc(a) a++
15 #define dec(a) a--
16 #define exit(a) return a
17 #define mod %
18 #define div /
19 #define shl <<
20 #define shr >>
21 #define extended long double
22 #define longint int
23 #define integer short
24 #define int64 long long
25 template<typename T> inline void read(T& a)
26 begin
27   T x=0,f=1; char ch=getchar();
28   while(ch<\'0\')or(ch>\'9\')do
29   begin
30     if ch==\'-\' then f=-1; ch=getchar();
31   end
32   while(ch>=\'0\')and(ch<=\'9\')do
33   begin
34     x=x*10+ch-\'0\'; ch=getchar();
35   end
36   a=x*f;
37 end
38 inline void readl()
39 begin
40   char ch; ch=getchar();
41   while ch!=\'\\n\' do ch=getchar();
42 end
43 int64 i,t,ii,j,n,m,x,a[3002],b[1000002],ans;
44 int main()
45 begin
46   read(t);
47   for ii=1;ii<=t;ii++ do
48   begin
49     read(x); j=sqrt(x); n=0; m=0; ans=0;
50     for i=1;i<=j;i++ do
51     begin
52       if x mod i==0 then
53       begin
54         inc(n); a[n]=i;
55         if x div i>i then begin inc(m); a[2002-m]=x div i; end;
56       end
57     end
58     for i=n+1;i<=n+m;i++ do a[i]=a[2002-(m-(i-n)+1)];
59     n=n+m;
60     for i=1;i<=n;i++ do b[a[i]]=0;
61     for i=n;i>=1;i-- do
62     begin
63       b[a[i]]=b[a[i]]+(1+x div a[i])*(x div a[i])div 2;
64       ans=ans+b[a[i]]*x;
65       j=1;
66       while a[j]*a[j]<=a[i] do
67       begin
68         if j>n then break;
69         if a[i] mod a[j]==0 then
70         begin
71           b[a[j]]=b[a[j]]-(a[i] div a[j])*b[a[i]];
72           if(a[j]*a[j]<a[i])and(a[j]>1)then
73           b[a[i] div a[j]]=b[a[i] div a[j]]-a[j]*b[a[i]];
74         end
75         inc(j);
76       end
77     end
78     write("%lld",ans); writeln;
79   end
80 end
View Code

 

标程(P++注意):

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define begin {
 4 #define end }
 5 #define while while(
 6 #define if if(
 7 #define do )
 8 #define then )
 9 #define for for(
10 #define fillchar(a,b,c) memset(a,c,b)
11 #define writeln printf("\\n")
12 #define write printf
13 #define readln readl()
14 #define inc(a) a++
15 #define dec(a) a--
16 #define exit(a) return a
17 #define mod %
18 #define div /
19 #define shl <<
20 #define shr >>
21 #define extended long double
22 #define longint int
23 #define integer short
24 #define int64 long long
25 template<typename T> inline void read(T& a)
26 begin
27   T x=0,f=1; char ch=getchar();
28   while(ch<\'0\')or(ch>\'9\')do
29   begin
30     if ch==\'-\' then f=-1; ch=getchar();
31   end
32   while(ch>=\'0\')and(ch<=\'9\')do
33   begin
34     x=x*10+ch-\'0\'; ch=getchar();
35   end
36   a=x*f;
37 end
38 inline void readl()
39 begin
40   char ch; ch=getchar();
41   while ch!=\'\\n\' do ch=getchar();
42 end
43 longint p[1000100],vis[1000100],ph[1000100],pcnt=0,T,n;
44 void init_p() 
45 begin
46   ph[1]=1; ph[2]=1;
47   int64 temp;
48   for int i=2;i<1000100;i++ do
49   begin
50     if not vis[i] then
51     begin
52       p[pcnt]=i; ph[i]=i-1; inc(pcnt);
53     end 
54     for int j=0;j<pcnt&&(temp=(int64)p[j]*i)<1000100;j++ do
55     begin
56       vis[temp]=1;
57       if i mod p[j]==0 then begin ph[temp]=ph[i]*p[j]; break; end
58       else ph[temp]=ph[i]*(p[j]-1);
59     end
60   end
61 end
62 int64 solve(int n)
63 begin
64   int64 ans=0ll;   
65   longint half=(int)(sqrt(n)+0.01);
66   if half*half==n then begin ans+=1ll*ph[half]*half/2; dec(half); end
67   inc(ans); ans+=1ll*ph[n]*n/2;
68   for int i=2;i<=half;i++ do
69   if n mod i==0 then
70   begin
71     ans+=1ll*ph[i]*i/2;
72     ans+=1ll*ph[n/i]*n/i/2;
73   end
74   exit(ans*n);
75 }
76 int main() 
77 begin
78   read(T); init_p();
79   for int i=1;i<=T;i++ do
80   begin read(n); write("%lld",solve(n)); writeln; end
81   return 0;
82 end
View Code

以上是关于BZOJ[SPOJ5971]LCMSum的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ2226][SPOJ5971]LCMSum(莫比乌斯反演)

BZOJ 2226 [Spoj 5971] LCMSum 最大公约数之和 | 数论

BZOJ 2226 [Spoj 5971] LCMSum

BZOJ 2226: [Spoj 5971] LCMSum

bzoj2226[Spoj 5971] LCMSum

[SPOJ 5971] LCMSum 莫比乌斯反演