Bzoj2705 Longge的问题

 

Time Limit: 3000MS Memory Limit: 131072KB 64bit IO Format: %lld & %llu

Description

Longge的数学成绩非常好,并且他非常乐于挑战高难度的数学问题。现在问题来了:给定一个整数N,你需要求出∑gcd(i, N)(1<=i <=N)。

Input

一个整数,为N。

Output

一个整数,为所求的答案。

Sample Input

6

Sample Output

15

Hint

 

【数据范围】

对于60%的数据,0<N<=2^16。

对于100%的数据,0<N<=2^32。

 

 

Source

SDOI2012

 

 

求Σgcd(i,n) (1<=i<=n)

暴力枚举当然可行,但是TLE不可避。

考虑转化问题,从1到n的范围内,有许多个i的gcd(i,n)等于同一个n的因数。我们可以枚举n的每一个因数k,累计“以该数k为解的gcd(i,n)的个数s(k)"乘以该数,就能得到答案。

若有gcd(n,m)=k,那么n和m同除公约数k后,可以得到gcd(n/k,m/k)=1。由前式可知(m/k)与(n/k)互质。满足条件的(m/k)个数,也就是s(k)就等于phi(n/k) ←欧拉函数!

 

解1:直接套模板。算法无误,但是因为题目数据大,保存函数后再处理会RE(原因目测是存储用数组开不了那么大)

 

 1 /*by SilverN*/
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 const int maxn=100000;
 9 long long n;
10 int m[maxn],phi[maxn],p[maxn],pt;
11 int euler()
12 {
13     phi[1]=1;
14     int N=maxn;
15     int k;
16     for(int i=2;i<N;i++)
17     {
18         if(!m[i])//i是素数
19             p[pt++]=m[i]=i,phi[i]=i-1;
20         for(int j=0;j<pt&&(k=p[j]*i)<N;j++)
21         {
22             m[k]=p[j];
23             if(m[i]==p[j])//为了保证以后的数不被再筛,要break
24             {
25                 phi[k]=phi[i]*p[j];
26 /*这里的phi[k]与phi[i]后面的∏(p[i]-1)/p[i]都一样(m[i]==p[j])只差一个p[j],就可以保证∏(p[i]-1)/p[i]前面也一样了*/
27                 break;    
28             }
29             else
30                 phi[k]=phi[i]*(p[j]-1);//积性函数性质,f(i*k)=f(i)*f(k)
31         }
32     }
33 }
34 int main(){
35     euler();
36     scanf("%lld",&n);
37     long long m=sqrt(n);
38     int i,j;
39     long long ans=0;
40     for(i=1;i<=m;i++){
41         if(n%i==0){
42             ans+=phi[n/i]*i;
43             ans+=(n/i)*phi[i];
44         }
45     }
46     printf("%lld\n",ans);
47     return 0;
48 }

 

 

 

 

解2:多花点时间,每次都算一遍。并不会TLE,神奇

代码是从hzw学长那学到的,精简得很。

 1 /*by SilverN*/
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 const int mxn=100000;
 9 long long n,m;
10 long long phi(long long x){
11     long long a=x;
12     for(long long i=2;i<=m;i++){
13         if(x%i==0){//找到因数 
14             a=a/i*(i-1);//基本计算公式 a*=((i-1)/i) 
15             while(x%i==0)x/=i;//除去所有相同因数 
16         }
17     }
18     if(x>1)a=a/x*(x-1);//处理最后一个大因数 
19     return a;
20 }
21 int main(){
22     scanf("%lld",&n);
23     m=sqrt(n);
24     int i,j;
25     long long ans=0;
26     for(i=1;i<=m;i++){
27         if(n%i==0){
28             ans+=phi(n/i)*i;
29             ans+=(n/i)*phi(i);
30         }
31     }
32     printf("%lld\n",ans);
33     return 0;
34 }

 

转载于:https://www.cnblogs.com/SilverNebula/p/5656723.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值