欧拉函数+中国剩余定理入门

欧拉函数

互质:

互质是公约数只有1的两个整数,叫做互质整数。公约数只有1的两个自然数,叫做互质自然数,后者是前者的特殊情形

  • 5和5不互质,因为5和5的公因数有1、5。
  • 1和任何数都成倍数关系,但和任何数都互质。因为1的因数只有1,而互质数的原则是:只要两数的公因数只有1时,就说两数是互质数。因为1只有一个因数所以1既不是质数(素数),也不是合数,无法再找到1和其他数的别的公因数了。1和-1与所有整数互素,而且它们是唯一与0互素的整数。
  • 互质数的写法:如c与m互质,则写作 ( c , m ) = 1 (c,m)=1 (c,m)=1

欧拉函数介绍:

  • 在数论,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目(因此φ(1)=1)。
  • 此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。
  • 从欧拉函数引伸出来在环论方面的事实和拉格朗日定理构成了欧拉定理的证明。

公式1:
φ ( x ) = x ∏ i = 1 n ( 1 − 1 p i ) ( 其 中 p 1 , p 2 … … p n 为 x 的 所 有 质 因 数 , x 是 不 为 0 的 整 数 ) \begin{aligned}\varphi \left( x\right) =x\prod ^{n}_{i=1}\left( 1-\dfrac{1}{p_{i}}\right) \\ \left(其中p_{1}, p_{2}……p_{n}为x的所有质因数,x是不为0的整数 \right) \end{aligned} φ(x)=xi=1n(1pi1)(p1,p2pnxx0)
公式2:
φ ( n ) = n − 1 ( n 为 质 数 ) \begin{aligned}\varphi \left( n\right) =n-1\\ \left( n为质数\right) \end{aligned} φ(n)=n1(n)

//常规求法
ll eular(ll n){
    ll ans = n;
    for(ll i=2; i<=sqrt(n); i++){
        if(n%i==0){
            ans = ans/i*(i-1);
            while(n%i==0)n/=i;
        }
    }
    if(n>1)ans = ans/n*(n-1);
    return ans;
}
//记忆化求法
void euler(){  
    for(int i=2;i<maxn;i++){  
        if(!Eu[i])
        for(int j=i;j<maxn;j+=i){  
            if(!Eu[j])Eu[j]=j;  
            Eu[j]=Eu[j]/i*(i-1);  
        }  
    }  
}

例题:

GCD(HDU-2588)

题意:

x < = n x <= n x<=n g c d ( x , n ) > = m gcd(x,n)>= m gcd(xn)>=m x x x的个数

思路:
gcd ⁡ ( x , N ) ≥ M ⇔ gcd ⁡ ( x M , N M ) ≥ 1 \gcd \left( x,N\right) \geq M\Leftrightarrow \gcd \left( \dfrac{x}{M},\dfrac{N}{M}\right) \geq 1 gcd(x,N)Mgcd(Mx,MN)1
gcd ⁡ ( x M , N M ) ≥ 1 ⇔ gcd ⁡ ( x α , N α ) = 1 ( α M ≥ 1 , α 没 必 要 是 M 的 倍 数 ) \begin{aligned}\gcd \left( \dfrac{x}{M},\dfrac{N}{M}\right) \geq 1\Leftrightarrow \gcd \left( \dfrac{x}{\alpha },\dfrac{N}{\alpha }\right) =1\\ \left( \dfrac{\alpha }{M}\geq 1,\alpha没必要是M的倍数\right) \end{aligned} gcd(Mx,MN)1gcd(αx,αN)=1(Mα1,αM)
先找出所有满足条件的 α \alpha α(首先是n的因数,然后比m大)值,之后利用欧拉函数,求出 x α \dfrac{x}{\alpha} αx的个数,最后累加个数即可

代码:

#include<iostream>
#include<stdio.h>
#include<cmath>
#define ll long long
using namespace std;
ll eular(ll n){
    ll ans = n;
    int g=(int)sqrt(n+0.5);
    for(ll i=2; i<=g; i++){
        if(n%i==0){
            ans = ans/i*(i-1);
            while(n%i==0)n/=i;
        }
    }
    if(n>1)ans = ans/n*(n-1);
    return ans;
}
int main(){
    int t;
    scanf("%d",&t);
    ll n,m;
    while(t--){
        scanf("%lld%lld",&n,&m);
        ll ans=0;
        for(ll i=1;i*i<=n;i++){
            if(n%i==0){//找出满足条件的α(i)值
                if(i>=m) ans+=eular(n/i);
                if(i*i!=n&&n/i>=m) ans+=eular(i);
            }
        }
        printf("%lld\n",ans);
    }
}

中国剩余定理

解如下方程:
( S ) : { x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) ⋮ x ≡ a n ( m o d m n ) \left( S\right) :\begin{cases}x\equiv a_{1}\left( modm_{1}\right) \\ x\equiv a_{2}\left( modm_{2}\right) \\ \vdots \\ x\equiv a_{n}\left( modm_{n}\right) \end{cases} (S):xa1(modm1)xa2(modm2)xan(modmn)
先取 M = ∏ i = 1 n m i M=\prod ^{n}_{i=1}m_{i} M=i=1nmi M i = M m i M_{i}=\dfrac{M}{m_{i}} Mi=miM

之后令 t i = M i − 1 t_{i}=M_{i}^{-1} ti=Mi1 M i M_{i} Mi m i m_{i} mi的数论倒数( t i t_{i} ti M i M_{i} Mi m i m_{i} mi意义下的逆元)

那么方程组 ( S ) (S) (S)的通解形式为
x = a 1 t 1 M 1 + a 2 t 2 M 2 + … + a n t n M n + k M = k M + ∑ i = 1 n a i t i M i , k ∈ Z \begin{aligned}x=a_{1}t_{1}M_{1}+a_{2}t_{2}M_{2}+\ldots +a_{n}t_{n}M_{n}+kM\\ =kM+\sum ^{n}_{i=1}a_{i}t_{i}M_{i},k\in Z\end{aligned} x=a1t1M1+a2t2M2++antnMn+kM=kM+i=1naitiMi,kZ

在模 M M M意义下,方程组 ( S ) (S) (S)只有一个解:
x = ( ∑ i = 1 n a i t i M i ) m o d M x=\left( \sum ^{n}_{i=1}a_{i}t_{i}M_{i}\right) modM x=(i=1naitiMi)modM

例题:

曹冲养猪

代码:

#include<iostream>
#include<stdio.h>
using namespace std;
typedef long long ll;
int a[15],b[15];
ll m=1,ans=0,p,q;
void exgcd1(ll a,ll b,ll &x,ll &y)
{
    if(b==0){x=1,y=0;return ;}
    exgcd1(b,a%b,y,x);
    y-=x*(a/b);
}//无返回值版 
ll exgcd2(ll a,ll b,ll &x,ll &y)
{
    if(!b){x=1, y=0; return a;}
    int gc=exgcd2(b,a%b,y,x);
    y-=a/b*x;
    return gc;
}//递归求ax+by=gcd(a,b),有返回值版 
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&a[i],&b[i]),m*=a[i];
    for(int i=1;i<=n;i++)
    {
        ll x=m/a[i];
        exgcd1(x,a[i],p,q);
        p=(p%a[i]+a[i])%a[i];//p的最小正整数解
        ans+=((p*b[i]*x)%m+m)%m;
        ans%=m;
 
    }
    printf("%lld",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值