csu(欧拉函数+筛素数)

这真是一道好题啊!让我wa了那么多次,wa的原因是:大于根号n的质因子有且只有一个,而我一开始都不懂这一点;

题目链接

题意:输入一个n,A是n的所有因子之和,B是所有与n互质的数之和,求A - B

B比较容易求,所以先分析一下如何求B,首先我们要知道一个结论如果x与n互质,那么n-x与n也互质,所以B = n * phi(n)/2;

然后求A,先求n的所有素因子分别为,p1,p2......pk,对应的个数为s1,s2,.......sk,举一个例子n = 12,那么素因子有2,3  ,对应的个数为2,1;


下面是代码:

#include<iostream>  
#include<algorithm>  
#include<cstring>  
#include<stack>  
#include<queue>  
#include<set>  
#include<map>  
#include<stdio.h>  
#include<stdlib.h>  
#include<ctype.h>  
#include<time.h>  
#include<math.h>  
    
#define ll long long  
#define N 100000 + 10   
#define eps 1e-9  
#define pi acos(-1.0)  
#define P system("pause")  
using namespace std;  
bool vis[N];  
int prime[N],number[N];  
int euler_phi(int n)  
{  
    int m = (int)sqrt(n + 0.5);  
    int ans = n;  
    for(int i = 2; i <= m ;i++)  
    {  
            if(n % i == 0)  
            {  
                 ans = ans / i * (i - 1);  
                 while(n % i == 0)  n /= i;       
            }          
    }      
    if( n > 1) ans = ans / n * (n - 1);  
    return ans;  
}  
    
//求10^5之间的素数  
void sieve(int n)  
{  
         
     memset(vis,0,sizeof(vis));  
     int m = (int) sqrt(n + 0.5);  
     for(int i = 2; i <= m; i++)  
             if(!vis[i])  
                   for(int j = i*i; j <= n; j += i)  
                        vis[j] = 1;                 
}  
     
int gen_primes(int n)  
{  
    sieve(n);  
    int c = 0;  
    for(int i = 2; i <= n; i++)  
          if(!vis[i])  
              prime[c++] = i;  
    return c;      
}  
ll pow(int a,int n)  
{  
    ll ans = 1;  
    ll b = (ll)a; 
    for(int i = 0; i < n; i++)  
            ans *= b;  
    return ans;                    
}  
struct node
{
       int x1,x2;       
}s[N];
int main()  
{  
//freopen("input.txt","r",stdin);  
//freopen("output.txt","w",stdout);  
    int c = gen_primes(100000);  
    int n;  
    while(scanf("%d",&n) != EOF)  
    {  
         if(n == 1) {  
                 printf("0\n");  
                 continue;       
         }  
         //for(int i = 1; i < n; i++)                                          
           //   cout<<euler_phi(i)<<endl;                                 
         ll B = (ll)n*(ll)euler_phi(n)/2;  
             
         memset(number,0,sizeof(number));  
         int i = 0;  
         int n1 = n;  
         while(n > 1 && i < c)  
         {  
              while(n % prime[i] == 0)  
              {  
                   number[i]++;  
                   n /= prime[i];             
              }             
              i++;  
         }  
        // cout<<n<<endl;
         ll A = 1;  
         for(i = 0; i < c && n1 >= prime[i]; i++)  
             A = A * (ll)( (pow(prime[i],number[i]+1) - 1 ) / (ll)(prime[i] - 1));  
         if(n > 1) //比根号n大的质因子只有一个,这是关键地方 
              A = A * (ll)(1 - (ll)n*(ll)n)/(ll)(1 - n);
         //cout<<A<<" "<<B<<endl;
         printf("%lld\n",A - B);  
                                                 
    }                                          
 // P;                                 
    return 0;      
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值