题目链接:
http://poj.org/problem?id=2478
解题思路:
通过观察,可以发现序列F(n)有以下特征:F(n-1)所具有的项,F(n)一定也具有。例如F(3)有1/3、1/2、2/3,F(4)也有这3项。所以我们关注的是F(n)与F(n-1)相比较所增加的项。最终我们可以了解到:F(n)与F(n-1)相比较,所增加的项的分母都是n,而分子与n互质。例如F(4)与F(3)相比较,增加的项是1/4、3/4。因此增加的项的数目是小于n且与n互质的数的个数,这些数的个数叫做欧拉函数。
欧拉函数的一条计算公式是:ψ(n)=n*(1-1/p1)*(1-1/p2)*......*(1-1/pk),其中p1、p2、......、pk是n的质因子。例如6的质因子有2、3,所以ψ(6)=2。我们可以把ψ(n)的计算公式变换一下,便于程序的编写:ψ(n)=n*[(p1-1)/p1]*[(p2-1)/p2]*......*[(pk-1)/pk]。要想求出ψ(n),就必须知道n的所有质因子。而对于这道题目,我们要计算的是2~10万的ψ(n)是多少,我们可以通过跟筛选素数类似的方法一次性把所有的欧拉函数求出来。首先我们可以先令所有的ψ(n)=n,把公式中的第一个n先弄出来。然后从2开始,凡是能被2整除的数,它的ψ(n)都要除以2,并且乘上(2-1),因为2是它的质因子。同时,能被2整除的这些数就不能作为质因子去寻找能被它整除的数,例如,4能被2整除,4就不能作为质因子去寻找能被4整除的数。计算完能被2整除的数以后,就计算能被3整除的数,计算完能被3整除的数以后,就计算能被5整除的数,此时4已被剔除掉,以此类推。
最终我们得到了所有的ψ(n),再根据递推关系计算F(n)。
具体代码:
#include<iostream>
#include<cstring>
#define MAXN 1000000
using namespace std;
long long phi[MAXN+1],F[MAXN+1];
bool vis[MAXN+1];
void calc()
{
memset(vis,0,sizeof(vis));
for(int i=2;i<=MAXN;i++)
phi[i]=i;
for(int i=2;i<=MAXN;i++)
if(!vis[i])
for(int j=i;j<=MAXN;j+=i)
{
phi[j]=phi[j]/i*(i-1);
vis[j]=1;
}
F[2]=phi[2];
for(int i=3;i<=MAXN;i++)
F[i]=F[i-1]+phi[i];
}
int main()
{
calc();
int n;
while(cin>>n&&n)
cout<<F[n]<<endl;
return 0;
}