uva 10820 Send a Table

数论题(筛法求救欧拉函数)

题意:输入n,[1,50000],定义一个二元组(x,y),满足1<=x,y<=n , 且x和y互质 , 要求输出二元组的个数。注意好像(2,3),(3,2)算作两个答案,所以我们只要求出一组答案再乘以2即可

关键是怎么找出这个二元组,其实就是筛法求欧拉函数

我们约定x<y且x与y互质,那么我们将y从1枚举到n,对于每个y,找出所有小于它并且与它互质的x的个数,这不就是求y的欧拉函数吗?而y从1到n,不就是求n以内所有数字的欧拉函数吗?

所以最后的答案,就是n以内每个数字的欧拉函数值的累加和*2-1,没什么减1,是因为一个特殊的数字1,1的欧拉函数值为1(它本身),在x2过程中算了两次(1,1)要减去一个。

因为数据固定在50000以内,所以我们先用筛法50000以内数字的欧拉函数值保存下来,然后再读入case , 时间是0.024s

//筛法构建欧拉函数
#include <cstdio>
#include <cstring>
#include <cmath>
#define N 50000
int phi[N+10];

void init()  //先用筛法算出50000以内每个数字的欧拉函数值
{
    memset(phi,0,sizeof(phi));  phi[1]=1; 
    for(int i=2; i<=N; i++)  if(!phi[i]) //质因子
        for(int j=i; j<=N; j+=i)
        {
            if(!phi[j]) phi[j]=j;
            phi[j]=phi[j]/i*(i-1);
        }
    return ;
}
int main()
{
    int n;
    init();
    while(scanf("%d",&n)!=EOF && n)
    {
        int ans=0;
        for(int i=1; i<=n; i++)  
            ans+=phi[i];
        ans=ans*2-1;
        printf("%d\n",ans);
    }
    return 0;
}

 

甚至我们可以用递推的思想,把50000以内的累加和都事先保存下来,需要的时候再x2-1 , 时间0.012s

//筛法构建欧拉函数
#include <cstdio>
#include <cstring>
#include <cmath>
#define N 50000
int phi[N+10];
int sum[N+10];
void init()  //先用筛法算出50000以内每个数字的欧拉函数值
{
    memset(phi,0,sizeof(phi));  phi[1]=1; 
    for(int i=2; i<=N; i++)  if(!phi[i]) //质因子
        for(int j=i; j<=N; j+=i)
        {
            if(!phi[j]) phi[j]=j;
            phi[j]=phi[j]/i*(i-1);
        }
    sum[1]=1;
    for(int i=2; i<=N; i++)
        sum[i]=sum[i-1]+phi[i];
    return ;
}
int main()
{
    int n;
    init();
    while(scanf("%d",&n)!=EOF && n)
        printf("%d\n",sum[n]*2-1);

    return 0;
}

 

 

posted @ 2013-01-18 23:54  Titanium  阅读(531)  评论(0编辑  收藏  举报