这里是枚举每一个最大公约数p,那么最后求的是f(n) = sigma(p*phi(n/p)) phi()为欧拉函数
这里可以试着算一下,然后会发现这个是积性函数的
那么只要考虑每一类质数分开算,最后乘在一起就行了
而对于f(p^k) p为素数的求解可以这样考虑
对于前一个f(p^(k-1)) , 那么f(p^k)相当于把f(p^(k-1)) 中的所有情况都乘上了p , 然后加上新产生的gcd()=1的情况,这个利用过程中的欧拉函数定理求解
phi(n) = (p1-1)*p1^(k1-1)....+(pn-1)*pn^(kn-1)
这里只能在只含有唯一素数因子的情况下计算,因为如果有别的素数因子,新产生的gcd除了1以外,还有当前乘上的因子p之外的素数因子考虑不到,会使答案变小,
这里大概想想就可以知道了
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <ctime> 6 #include <cstdlib> 7 using namespace std; 8 #define ll long long 9 #define N 100000 10 int prime[N+5] , tot , fai[N+5]; 11 bool check[N+5]; 12 13 void get_prime() 14 { 15 for(int i=2 ; i<=N ; i++){ 16 if(!check[i]){ 17 prime[tot++] = i; 18 fai[i] = i-1; 19 } 20 for(int j=0 ; j<tot ; j++){ 21 if((ll)prime[j]*i>N) break; 22 check[prime[j]*i] = true; 23 if(i%prime[j]==0){ 24 fai[i*prime[j]] = fai[i]*prime[j]; 25 break; 26 }else fai[i*prime[j]] = fai[i]*(prime[j]-1); 27 } 28 } 29 } 30 31 void solve(int n) 32 { 33 /*这里求出一个gcd(i,n)=1的个数,就是求n的欧拉函数phi(n) 34 phi(n) = (p1-1)*p1^(k1-1)....+(pn-1)*pn^(kn-1) 35 */ 36 ll ret = 1; 37 for(int i=0 ; i<tot ; i++){ 38 if(prime[i]>n) break; 39 int cnt = 0; 40 ll phi = 0 , tmp = 1; 41 while(n%prime[i]==0){ 42 if(!cnt) phi = prime[i]-1; 43 else phi = phi*prime[i]; 44 tmp = tmp*prime[i]+phi; 45 cnt++; 46 n/=prime[i]; 47 } 48 ret = ret*tmp; 49 } 50 if(n>1){ 51 ret = ret*(2*(ll)n-1); //这里的n可能是超过1e9的整数,*2有可能超int,要注意 52 // if(ret<0) cout<<"last "<<n<<" "<<(2*n-1)<<" "<<ret<<endl; 53 } 54 printf("%I64d\n" , ret); 55 } 56 int main() { 57 // freopen("a.in" , "r" , stdin); 58 // freopen("out.txt" , "w" , stdout); 59 get_prime(); 60 int n; 61 while(~scanf("%d" , &n)){ 62 solve(n); 63 } 64 }
时间: 2024-10-13 16:21:09