数学知识-欧拉函数&快速幂

欧拉函数

定义

对于正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目,记作φ(n).

 

 算法思路

既然求解每个数的欧拉函数,都需要知道他的质因子,而不需要个数

因此,我们只需求出他的质因子,然后根据公式:N*(p1-1)/p1*(p2-1)/p2......即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;

int main()
{
    ll i,j;
    cin>>n;
    for(i=0;i<n;i++)
    {
        ll x;
        cin>>x;
        ll ans=x;
        for(j=2;j<=x/j;j++)
        {
            if(x%j==0)
            {
                ans=ans*(j-1)/j;
                while(x%j==0)
                {
                    x/=j;
                }
            }
        }
        if(x!=1)
            ans=ans*(x-1)/x;
        cout<<ans<<endl;
    }
    return 0;
}

筛法求欧拉函数

问题

给定一个正整数n,求1~n中每个数的欧拉函数之和。

算法思路

使用线性筛的方法,来求每个数的欧拉函数

 

 

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,cnt;
bool st[N];
int primes[N];
int phi[N];


void get_eulers()
{
    int i,j;
    phi[1]=1;
    for(i=2;i<=n;i++)
    {
        if(!st[i])
        {
            primes[cnt++]=i;
            phi[i]=i-1;
            for(j=0;primes[j]<=n/i;j++)
            {
                st[primes[j]*i]=true;
                if(i%primes[j]==0)
                    phi[primes[j]*i]=primes[j]*phi[i];
                else
                    phi[primes[j]*i]=(primes[j]-1)*phi[i];
            }
        }
    }
    int ans=0;
    for(i=1;i<=n;i++)
        ans+=phi[i];
    cout<<ans<<endl;
}

int main()
{
    int i,j;
    cin>>n;

    get_eulers();

    return 0;
}

快速幂

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

void suppow(ll a,ll b,ll p)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%p;
        a=(a*a)%p;
        b>>=1;
    }
    cout<<ans%p<<endl;
}

int main()
{
    ll n,a,b,p;
    cin>>n;
    while(n--)
    {
        cin>>a>>b>>p;
        suppow(a,b,p);
    }


    return 0;
}

快速幂求逆元

前提

 

 代码

快速幂求解:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;

ll supow(ll a,ll b,ll p)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}

int main()
{
    ll a,p,n;
    cin>>n;
    while(n--)
    {
        cin>>a>>p;
        if(a%p!=0)
        {
            cout<<supow(a,p-2,p)<<endl;
        }
        else
            puts("impossible");
    }
    return 0;
}

扩展欧几里得求逆元

#include <iostream>
using namespace std;
typedef long long LL;
int n;

int exgcd(int a, int b, int &x, int &y)
{
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}


int main()
{
    cin >> n;
    while (n --)
    {
        int a, p, x, y;
        // if (a < p) swap(a, p);
        cin >>  a >> p;
        int d = exgcd(a, p, x, y);
        if (d == 1) cout << ((LL)x + p) % p << endl;//保证x是正数
        else puts("impossible");

    }
    return 0;
}

 

posted @ 2021-02-09 16:15  清风紫雪  阅读(236)  评论(0编辑  收藏  举报