https://vj.xtuacm.cf/contest/view.action?cid=146#problem/D
参考:http://www.cnblogs.com/xiaowuga/p/7161513.html
http://www.cnblogs.com/xiaowuga/p/7161513.html
这个题需要用到欧拉函数的知识……
欧拉函数的定义:对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(我们定义φ(1)=1)
欧拉函数的的通式:φ(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)……*(1-1/ps)(p1,p2,p3,……ps均是n的质因子)
欧拉函数有这么几个比较重要的性质:
性质1:如果n是质数p的k次幂,那么φ(n)=p^k-1*(p-1)
性质2:欧拉函数是积性函数——若m,n互质,φ(mn)=φ(n)*φ(m),积性函数和完全积性函数有区别,有兴趣可以自己百度一下
性质3:当n为奇数的时候,φ(2n)=φ(n),这一点是由性质2推出来的,因为2必定和所有的奇数都是互质的,所以而φ(2)=1。所以得出这个结果
性质4:n的所有质因子之和等于φ(n)*n/2(这不算性质,只能算延伸)。
好了,大体介绍完了欧拉函数,我们可以开始来看看这个题怎么做了。
首先要知道gcd(i,n)是积性函数(当n固定时),也就是说gcd(i*j,n)=gcd(i,n)*gcd(j,n)(这里还有一个限制条件,就是i,j互质,所以gcd并非完全积性函数)
好了现在我们需要来学习真正的姿势了,我也是刚学的,利用gcd是积性函数的性质,根据前文说的,我们有这样的结论:n>1时 n=p1^a1*p2^a2*…ps^as,p为n的质因子,那么f(n)是积性函数的充要条件是f(1)=1,及f(n) = f(p1^a1)*f(p2^a2)…f(pr^ar),所以只要求f(pi^ai)就好。现在来看具体做法。
f(pi^ai) = Φ(pi^ai)+pi*Φ(pi^(ai-1))+pi^2*Φ(pi^(ai-2))+…+pi^(ai-1)* Φ(pi)+ pi^ai *Φ(1)
根据性质1,我们可以做出如下化简
f(pi^ai)=[pi^(ai-1)(pi-1) ] + [pi*pi^(ai-2)(pi-1)] + [pi^2*pi^(ai-3)(pi-1)] + [pi^3*pi^(ai-4)(pi-1)]….[pi^(ai-1)pi^(ai-ai)(pi-1)]+pi^ai ①
然后对①提取公因子(pi-1)
f(pi^ai)=(pi-1){[pi^(ai-1) ] + [pi*pi^(ai-2)] + [pi^2*pi^(ai-3)] + [pi^3*pi^(ai-4)]….[pi^(ai-1)*pi^(ai-ai)]+[pi^ai/(pi-1)]} ②
紧接着我们发现出了最后一项每个[]每个方括号内乘积都等于pi^(ai-1),所以对②提取公因子pi^(ai-1)
f(pi^ai)=(pi-1)pi^(ai-1){ai+[pi/(pi-1)]} ③
然后把(pi-1)/pi放进括号里得
f(pi^ai)=pi^(ai){1+ai(pi-1)/pi} ④
这个 ④是单个f(pi^ai)的公式,我们提取所有的pi^(ai)相乘实际上就是n了,所以我们可以得到f(n)的公式:f(n)=n*∏(1+ai*(pi-1)/pi)
代码:
#include<stdio.h>
int main()
{
long long n;
while(scanf("%I64d",&n)!=EOF)
{
long long i;
long long ans=n;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
{
long long a=0;
while(n%i==0)
{
a++;
n/=i;
}
ans=ans+ans*a*(i-1)/i;
}
}
if(n>1)
ans=ans/n*(n+n-1);
printf("%I64d\n",ans);
}
return 0;
}
这是第一次做的代码,用时较长:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
int cnt,a[100];
ll euler (ll n)
{
ll ans=1;
for(ll i=2; i*i<=n; i++)
{
if(n%i)
continue;
ans*=i-1;
n=n/i;
while(n%i==0)
{
n=n/i;
ans*=i;
}
}
if(n>1)ans*=(n-1);
return ans;
}
void fen(ll n)
{
ll s=sqrt(n);
for(ll i=1; i<=s; i++)
{
if(n%i==0)
{
a[cnt++]=i;
if(i!=(n/i))
a[cnt++]=n/i;
}
}
}
int main()
{
ll n;
while(~scanf("%I64d",&n))
{
memset(a,0,sizeof(a));
cnt=0;
fen(n);
ll s=sqrt(n);
ll ans=0;
for(ll i=0; i<cnt; i++)
{
ans+=(euler(n/a[i])*a[i]);
//cout<<ans<<endl;
}
printf("%I64d\n",ans);
}
return 0;
}