前传:本来之前在高中的一个OJ上看见的,SDOI上的一个题,看着很“数论”,想了想,没想法。。。看了看DISCUSS,说是POJ上的原题,然后看了一下DISCUSS说是欧拉函数,不会。。。然后就放下,最近遇见了很多这样类似的问题,所以先把这个裸题给过了。。。查了一下,有结论。。。
∑gcd(i, n) = sum(i*euler(n/i));为啥会这样呢?我自己手算了一下10的情况,规律还是挺明显的,1-n中可以整除i的个数是n/i,这些数与n的最大公约数为i的时候,不就相当于这些都数除以i,然后寻找互质的数,所以i*euler(n/i)就是1-n中公约数是i的总和。欧拉函数用的是模版,本来还想推导一下,实在是没想出这个公式怎么来的,先用着吧。
PS:没注意n是完全平方数的情况,错了两次。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <vector> 6 #include <cmath> 7 #include <map> 8 #define ll __int64 9 using namespace std; 10 ll euler(ll n) 11 { 12 ll i,m = (ll)sqrt(n + 0.5),ans = n; 13 for(i = 2;i <= m;i ++) 14 { 15 if(n%i == 0) 16 ans = ans/i*(i-1); 17 while(n%i == 0) n /= i; 18 } 19 if(n > 1) ans = ans/n*(n-1); 20 return ans; 21 } 22 int main() 23 { 24 ll n,ans,i; 25 while(scanf("%I64d",&n)!=EOF) 26 { 27 ans = 0; 28 for(i = 1;i*i <= n;i ++) 29 { 30 if(n%i == 0) 31 { 32 ans += i*euler(n/i); 33 if(i*i != n) 34 ans += n/i*euler(i); 35 } 36 } 37 printf("%I64d\n",ans); 38 } 39 return 0; 40 }