这真是一道好题啊!让我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;
}