UVa10820

来源:互联网 发布:成都网络断连 编辑:程序博客网 时间:2024/06/17 06:06

题目链接

简介:
有某个函数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;}
原创粉丝点击