zoukankan      html  css  js  c++  java
  • 欧拉函数小结 hdu2588+

    从费马小定理到欧拉定理 欧拉公式 再到欧拉函数。,。 小结一下欧拉函数吧

    正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)----定义

    欧拉函数的基本公式其中pi为x的素因子 。公式的推导根据欧拉公式(积性函数的性质)+算术基本定理+phi(p^k)=p^k-p^(k-1)(p为素数)

    简单应用

    1.hdu 2588

    题意:给定N,M求gcd(i,N)>=M的i的个数(1<=i<=N,M<=N)

    题解 :  对于每个i因为i<=N 所以g=gcd(N,i)一定是N的因子 ,那么我们可以枚举N的所有因子g,设theta(g)为每个因子g对应的解的集合,那么theta(g1)+theta(g2)+...theta(gn)就是我们要的最终结果。(喵的网上看了一堆评论 说的都不怎么合理,自己整理一下)对于每一个因子g,最小的满足g=gcd(i,n)的i就为g(因为g一定为n的因子),这里要求的是gcd(i,n)>=M的情况,那么gcd(i*x,n)(1<=x<=(n/i))的情况也是满足的,为了避免和其他因子枚举出的结果产生重复的结果,也就是i*x不能等于q*z,q为n的其他因子。i*x能够变成其他因子枚举结果的条件是x与(n/i)不互质(两个数不互质,说明他们有相同的数根,这里i如果乘上一个与(n/i)不互质的数,那么就会成为n的其他因子(用反证法证明:这里我们把n划为i、n/i两个部分,i乘上一个与n/i不互质的数字p=k*t,k为gcd(n/i,p),那么i*p=i*k*t,这里i*k一定为n的因子))

    由于数据很大 ,我们在枚举的时候有一个小技巧,具体看代码。

    ac代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    using namespace std;
    int euler(int key)// 对比较大的数 用这个方法求比较有效
    {
        if(key==1) return 1;
        int temp=key;
        for(int i=2; i*i<=key ;i++)// 利用算术基本定理
        {
            if(key%i==0)
            {
                temp=temp/i*(i-1);
                while(key%i==0) key/=i;// 关键步骤 很有意思
            }
        }
        if(key > 1) temp=temp/key*(key-1);//
        return temp;
    }
    /*
    int eu[10000];
    int geteuler()// 对数据小的情况 用筛法可以有效求出多个数的euler
    {
        for(int i=1;i<=10000;i++) eu[i]=i;
        for(int i=2;i<=10000;i++)
        {
            if(eu[i]==i)
            {
                for(int j=i;j<=10000;j++)
                {
                    eu[j]=eu[j]/i*(i-1);
                }
            }
        }
    }
    */
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            int n,m;
            cin>>n>>m;
            int sum=0;
            for(int i=1;i*i<=n;i++)// 因子总是成对出现的 我们枚举的时候 只用枚举一边就可以了
            {
                if(n%i==0)// 是约数
                {
                    int key=n/i;
                    if( i>=m ) sum+=euler(key);
                    if( key>=m && i*i!=n) sum+=euler(i);// 避免i*i的情况计算两次
                }
            }
            cout<<sum<<endl;
        }
        return 0;
    }

    2.hdu 3501

    题意:求小于n且不与n互素的数之和

    题解:有一个知识点。 当i<=n  if gcd(n,i)=1 then gcd(n,n-i)=1;

           我们用  反证法来看  这个 假设gcd(n,i)=1 gcd(n,n-i)=k (k!=1) 那么就有 n%k==0 (n-i)%k==0-> n=i(mod k) 这个结论与前面gcd(n,i)=1矛盾 所以 if gcd(n,i) then gcd(n,n-i)=1。有这个结论就好解决这道题目了。我们求小于n且不于n互素的数之和,只要用小于n的数之和减去与n互素的数之和。由于和n互素的数字都是成对出现的,且和为n。

    ac代码:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const ll mod=1000000007;
    ll euler(ll n)
    {
        ll temp=n;
        for(ll i=2;i*i<=n;i++)
        {
            if(n%i==0)
            {
                temp=temp/i*(i-1);
                while(n%i==0) n/=i;
            }
        }
        if(n>1) temp=temp/n*(n-1);
        return temp;
    }
    int main()
    {
        ll n;
        while(cin>>n&&n)
        {
            if(n==2)
            {
                cout<<0<<endl;
                continue;
            }
            ll temp=n*(n+1)/2-n;
            ll zz;
            zz=euler(n)/2*n;
            zz=(temp-zz)%mod;
            if(zz<0) zz+=mod;
            cout<<zz<<endl;
        }
        return 0;
    }

    一步一个脚印才是实实在在的进步。共勉。。。

        

  • 相关阅读:
    svn command line tag
    MDbg.exe(.NET Framework 命令行调试程序)
    Microsoft Web Deployment Tool
    sql server CI
    VS 2010 One Click Deployment Issue “Application Validation did not succeed. Unable to continue”
    mshtml
    大厂程序员站错队被架空,只拿着五折工资!苟活和离职,如何选择?
    揭秘!Windows 为什么会蓝屏?微软程序员竟说是这个原因...
    喂!千万别忘了这个C语言知识!(~0 == -1 问题)
    Linux 比 Windows 更好,谁反对?我有13个赞成理由
  • 原文地址:https://www.cnblogs.com/z1141000271/p/7160763.html
Copyright © 2011-2022 走看看