【BZOJ】【2705】【SDOI2012】Longge的问题

欧拉函数/狄利克雷卷积/积性函数


  

2705: [SDOI2012]Longge的问题

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1275  Solved: 820
[Submit][Status][Discuss]

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

[Submit][Status][Discuss]

 

  掉到莫比乌斯反演的坑里无法自拔,问了zyf&在网上看了题解才做出来TAT……我果然好弱

  这个题是要求$\sum_{x=1}^{n}gcd(x,n)$,考虑它的实际意义,我们可以得到$ans=\sum_{i|n}i*\varphi(\frac{n}{i})$

  但是明显φ函数我们是没法预处理的……($\frac{n}{i}$这玩意太大了),但考虑到n的约数不会太多,所以我们可以边找因数边计算φ。

 1 /**************************************************************
 2     Problem: 2705
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:16 ms
 7     Memory:804 kb
 8 ****************************************************************/
 9  
10 //BZOJ 2705
11 #include<cmath>
12 #include<cstdio>
13 #define F(i,j,n) for(int i=j;i<=n;i++)
14 typedef long long LL;
15 LL phi(LL n){
16     int ret=1,i;
17     for(int i=2;i*i<=n;i++){
18         if (n%i==0){
19             n/=i; ret*=i-1;
20             while(n%i==0) n/=i,ret*=i;
21         }
22     }
23     if (n>1) ret*=n-1;
24     return ret;
25 }
26 int main(){
27     int n;
28     scanf("%d",&n);
29     long long ans=0;
30     for(int i=1;i*i<=n;i++)
31         if(n%i==0){
32             ans+=(LL)i*phi(n/i);
33             if (i*i<n) ans+=(LL)n/i*phi(i);
34         }
35     printf("%lld\n",ans);
36     return 0;
37 }
View Code

  但是其实对于这个函数$\sum_{i|n} i*\varphi(\frac{n}{i})$是满足积性的,因为它就是$id(x)=x$和$\varphi(x)$这两个函数的狄利克雷卷积,那么……(贴个网上的图片)

 1 /**************************************************************
 2     Problem: 2705
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:8 ms
 7     Memory:816 kb
 8 ****************************************************************/
 9  
10 //BZOJ 2705
11 #include<cmath>
12 #include<cstdio>
13 #define F(i,j,n) for(int i=j;i<=n;i++)
14 int main(){
15     int n;
16     scanf("%d",&n);
17     long long ans=n;
18     F(i,2,sqrt(n)){
19         if(n%i==0){
20             int k=0;
21             for(k;n%i==0;k++,n/=i);
22             ans+=ans*(i-1)*k/i;
23         }
24     }
25     if (n!=1) ans+=ans*(n-1)*1/n;
26     printf("%lld\n",ans);
27     return 0;
28 }
View Code(诡异的加法版本)

P.S.但是这个【乘起来】的过程我在网上没找到啊……写法好诡异我理解不了……所以我机(sha)智(bi)地改了一个利用快速幂的版本= =耗时居然一样……如果有哪位路过的大牛搞明白了前面那个加法版本的意思的话请留言教我一下,万分感谢。

 1 /**************************************************************
 2     Problem: 2705
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:8 ms
 7     Memory:816 kb
 8 ****************************************************************/
 9  
10 //BZOJ 2705
11 #include<cmath>
12 #include<cstdio>
13 #define F(i,j,n) for(int i=j;i<=n;i++)
14 typedef long long LL;
15 LL Pow(LL a,LL b){
16     LL r=1;
17     for(;b;b>>=1,a*=a)if(b&1)r*=a;
18     return r;
19 }
20 int main(){
21     int n;
22     scanf("%d",&n);
23     LL ans=1;
24     F(i,2,sqrt(n)){
25         if(n%i==0){
26             int k=0;
27             for(k;n%i==0;k++,n/=i);
28             ans*=(k+1)*Pow(i,k)-k*Pow(i,k-1);
29 //            ans+=ans*(i-1)*k/i;
30         }
31     }
32     if (n!=1) ans*=2*Pow(n,1)-1;
33     printf("%lld\n",ans);
34     return 0;
35 }
View Code(乘法版本)

 

posted @ 2015-04-03 11:51  Tunix  阅读(243)  评论(1编辑  收藏  举报