《数论及应用》第6章 乘性函数问题(上)

1.欧拉函数:

关于欧拉函数,求的是指不超过n的与n互素的正整数的个数,按一般思想就是对数n进行素因子分解之后,所有的素数幂的欧拉函数之积

定理:设p是一个素数,a是正整数,那么 φ (p^a)=p^a-p^(a-1)

推论:若n是奇数,φ(2n)=φ(n)

两个常用定理:

欧拉定理:对任何两个互质的正整数a,m(m>=2)有a^φ(m)≡1(mod m)

费马小定理:当m是质数的时候,a^(m-1)≡1(mod m)

欧拉函数的算法实现:

//递归求欧拉
#include <stdio.h>
#define maxn 10000
int phi[maxn];
//个人觉得这个时间比较慢,
//而且你懂的,数组的大小是有限的,
//如果是求大数的就不行了
void Phi()
{
    for(int i=1;i<=maxn;i++)
        phi[i]=i;
    for(int i=2;i<=maxn;i+=2)
        phi[i]/=2;
    for(int i=3;i<=maxn;i+=2)
        if(phi[i]==i)
            for(int j=i;j<=maxn;j+=i)
                phi[j]=phi[j]/i*(i-1);
}

然后是一种单独求欧拉值的:

//单独求欧拉函数
#include <stdio.h>
#include <math.h>
//如果必要,可以改成long long
unsigned euler(unsigned x)
{
    unsigned i,res=x;
    for(i=2;i<=sqrt(x*1.0);i++)
        if(x%i==0)
        {
            res=res/i*(i-1);
            while(x%i==0)
            x/=i;
        }
    if(x>1)
    res=res/x*(x-1);
    return res;
}

还有一种素数表实现欧拉值的写法:

//传说这貌似时间最少
//用是时间是O(n) n是sqrt(x)内的素数的个数
//写起来好像跟前面的没什么很大的区别
#include <stdio.h>
#include <string.h>
int prime[50000];
int p[20000];
void Prime()
{
    memset(prime,1,sizeof(prime));
    prime[0]=prime[1]=0;
    for(int i=2;i*i<=50000;i++)
    if(prime[i])
    for(int j=2*i;j<=50000;j+=i)
    prime[j]=0;
    int k=0;
    for(int i=0;i<=50000;i++)
    {
        if(prime[i])
        p[++k]=i;
    }
}
int phi(int n)
{
    int res=n;
    for(int i=1;p[i]*p[i]<=n;i++)
    if(n%p[i]==0)
    {
        res=res-res/p[i];
        do
        n/=p[i];
        while(n%p[i]==0);
    }
    if(n>1)
    res=res-res/n;
    return res;
}

欧拉函数的应用:

http://poj.org/problem?id=2407

就是模板题,直接求出欧拉值

水题

#include <stdio.h>
long long euler(long long x)
{
    long long i,res=x;
    for(i=2;i*i<=x;i++)
      if(x%i==0)
      {
          res=res/i*(i-1);
          while(x%i==0)
          x/=i;
      }
    if(x>1)
    res=res/x*(x-1);
    return res;
}
int main()
{
    long long n;
    while(scanf("%I64d",&n)!=EOF,n)
    {
        printf("%I64d\n",euler(n));
    }
    return 0;
}

http://poj.org/problem?id=1284

求原根

所谓原根指的是http://zh.wikipedia.org/wiki/原根  反正是不好玩的东西

#include <stdio.h>
int euler(int x)
{
    int i,res=x;
    for(i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            res=res/i*(i-1);
            while(x%i==0)
            x/=i;
        }
    }
    if(x>1)
    res=res/x*(x-1);
    return res;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        printf("%d\n",euler(n-1));
    }
    return 0;
}

http://poj.org/problem?id=2478

还是欧拉函数的应用,求的是从2到n的欧拉值之和

这个题REWA TLE MLE 多次。。。RE是因为没有注意到数据类型,数组开大了就MLE了,然后换了筛素数的方法求欧拉值结果WA了,改对之后又是RE了   唉   伤不起啊    给一个水题坑死了

算了  坑就坑吧  把试过的几次代码都贴上

//这个时间用了235ms
#include <cstdlib>
#include <iostream>
using namespace std;
#define maxn 1000001
long long a[maxn];
int main()
{
    long long i,j;
    for(i=1;i<=maxn;i++) a[i]=i;
    for(i=2;i<=maxn;i+=2) a[i]/=2;
    for(i=3;i<=maxn;i+=2) if(a[i]==i)
    {
        for(j=i;j<=maxn;j+=i)
            a[j]=a[j]/i*(i-1);
    }
    for(i=3;i<maxn;i++)
    a[i]+=a[i-1];
    long long n;
    while(cin>>n&&n)
    cout<<a[n]<<endl;
    return 0;
}

//这个时间用了79ms
#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 1000001
bool isprime[maxn];
long long prime[maxn];
long long phi[maxn];
long long ans[maxn];
void getprime()
{
    long long k=0;
    for(int i=0;i<=maxn;i++)
    isprime[i]=1;
    for(int i=2;i<=maxn;i++)
    {
        if(isprime[i])
        {
            prime[k++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<k&′[j]*i<=maxn;j++)
        {
            isprime[i*prime[j]]=0;
            if(i%prime[j]!=0)
            {
                phi[i*prime[j]]=phi[i]*phi[prime[j]];
            }
            else
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
        }
    }
}
int main()
{
    getprime();
    ans[1]=0;
    for(int i=2;i<=maxn;i++)
    ans[i]=ans[i-1]+phi[i];
    int n;
    while(scanf("%d",&n),n)
    {
        printf("%I64d\n",ans[n]);
    }
    return 0;
}

//这个用了94ms
#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 1000001
bool isprime[maxn];
long long prime[maxn];
long long phi[maxn];
long long ans[maxn];
void getprime()
{
    long long k=0;
    for(int i=0;i<=maxn;i++)
    isprime[i]=1;
    for(int i=2;i<=maxn;i++)
    {
        if(isprime[i])
        {
            prime[k++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<k&′[j]*i<=maxn;j++)
        {
            isprime[i*prime[j]]=0;
            if(i%prime[j]!=0)
            {
                phi[i*prime[j]]=phi[i]*phi[prime[j]];
            }
            else
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
        }
    }
}
int main()
{
    getprime();
    ans[1]=0;
    for(int i=2;i<=maxn;i++)
    ans[i]=ans[i-1]+phi[i];
    int n;
    while(scanf("%d",&n),n)
    {
        printf("%I64d\n",ans[n]);
    }
    return 0;
}


http://poj.org/problem?id=3090

根据理解将平面划分为两个区域,中间那一线的当然只看得到最近的点(1,1) 至于其他的就只看得到,与输入的n值所互质的数的个数,总的意思还是求1到n的欧拉值之和

#include <stdio.h>
#define maxn 10000
int phi[maxn];
int main()
{
    for(int i=1;i<=maxn;i++)
        phi[i]=i;
    for(int i=2;i<=maxn;i+=2)
        phi[i]/=2;
    for(int i=3;i<=maxn;i+=2)
    {
        if(phi[i]==i)
        {
            for(int j=i;j<=maxn;j+=i)
            phi[j]=phi[j]/i*(i-1);
        }
    }
    for(int i=2;i<=maxn;i++)
    phi[i]+=phi[i-1];
    int n,t;
    scanf("%d",&t);
    int tt=0;
    while(t--)
    {
        scanf("%d",&n);
        printf("%d %d %d\n",++tt,n,2*phi[n]+1);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值