简介:
有某个函数f(x,y),根据f(x,y)可以很简单的算出f(x*k,y*k)
现在的问题是,要想算出0 < x,y <=n范围内的所有f,要记录多少原始值呢
分析:
一旦知道了这道题的本质,就一点都不难了,所以这道题的重点在于转化:
不难发现,一旦x和y的gcd的不是1的话,我们都可同时约掉gcd(x,y),因此这样的x和y是不需要记录的
换句话说:x,y必须互质
问题就转化成了:0 < x,y <=n,x和y互质的二元组(x,y)个数
为了方便计算,我们设x < y,这样最后答案只要*2就可以了
当y确定的时候,与y互质的x的个数就是phi(y)
因此枚举y,每个y的贡献就是phi(y)
ans=2*( phi(1)+phi(2)+phi(3)+…+phi(n) )-1
-1是因为phi(1)=1,但是二元组(1,1)只用计算一次
写到这里,才发现这道题和仪仗队一样
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=50005;
int sshu[N<<2],tot=0;
bool no[N];
int phi[N];
void prime()
{
memset(no,0,sizeof(no));
for (int i=2;i<N;i++)
{
if (!no[i]) sshu[++tot]=i;
for (int j=1;j<=tot&&sshu[j]*i<N;j++)
{
no[sshu[j]*i]=1;
if (i%sshu[j]==0) break;
}
}
}
void makephi()
{
for (int i=1;i<N;i++) phi[i]=i;
for (int i=1;i<=tot;i++)
for (int j=sshu[i];j<N;j+=sshu[i])
{
phi[j]/=sshu[i];
phi[j]*=(sshu[i]-1);
}
for (int i=2;i<N;i++) phi[i]+=phi[i-1];
}
int main()
{
prime();
makephi();
int n;
while (scanf("%d",&n)!=EOF&&n)
{
printf("%d\n",phi[n]*2-1);
}
return 0;
}