zoukankan      html  css  js  c++  java
  • 扩展欧拉定理

    扩展欧拉定理

    前置芝士

    欧拉定理

    定义

    对于a与m不一定互质的情况,有:

    [a^c~equiv~egin{cases}a^{cmodvarphi(m)} &gcd(a,m)~=~1 \a^c &gcd(a,m)~ eq~1~且~c~<~varphi(m) \ a^{cmodvarphi(m)+varphi(m)}&gcd(a,m)~ ot=~1~且~c~>=~varphi(m)end{cases} ]

    推论

    (m=1) 时明显成立,接下来讨论 (m ot=1) 的情况。

    对于 (gcd(a,m)=1) 的情况,因为 (a^{varphi(m)}equiv 1pmod m) ,所以每 (varphi(m))(a) 就相当于乘 (1) 。于是只需要算

    (cmodvarphi(m)) 次。

    对于 (c<varphi(m)) 的情况,直接爆算

    下面证明第三种情况。

    先证明 (a) 是一个质数的情况:

    引理1

    (forall p) 为质数,(rin Z^+) ,都有 (varphi(p^r)=(p-1) imes p^{r-1})

    证明:

    由于p是一个质数,所以 (1sim (p^r-1)) 中有且仅有 (i imes p,iin (0,p^{r-1}))(p^r) 不互质。

    于是 (varphi(p^r)=p^r-p^{r-1}=p^{r-1} imes (p-1))

    证毕
    引理2

    (forall~kin Z)(exists~a,b,x,yin Z^+,x^a imes y^b=k) ,都有 (a,bleqvarphi(k))

    证明

    先考虑k为一个质数p的r次幂的情况。根据引理1有:

    [varphi(k)=varphi(p^r)=(p-1) imes p^{r-1} ]

    下面说明 ((p-1) imes p^{r-1}geq r)

    当p=2时:

    经验证(~r=1,2,3~)时成立。当(~r>3~)时按照r的大小做数学归纳,可证正确性。

    (~p~>~2~)时,不等号左侧增大,右侧不变,不等式仍然成立。

    考虑k是多个质数幂时的情况,按照质数个数做数学归纳,正确性成立。

    任意组合质数,引理得证。

    证毕
    引理三:

    (exists~r~leq~c~,a^{varphi(m)+r}~equiv~a^rpmod m。)

    证明:

    (m=t imes a^r) ,其中 (gcd(t,a)=1) ,t的存在性显然

    因为 (gcd(t,a)=1) ,且 (varphi) 函数是一个积性函数,所以 (varphi(t)|varphi(m))

    根据欧拉定理,(a^{varphi(t)}~equiv~1~pmod t) ,于是:

    [a^{varphi(m)}~equiv~1~pmod t ]

    同余式同乘 (a^r) ,于是:

    [a^{varphi(m)+r}~equiv~a^r~pmod m ]

    已经证明可以构造出这样的r。根据引理2,(r~leq~varphi(m))。又 (c~geq~varphi(m)),于是可证构造出的(r~leq~c)。定理得证。

    证毕

    于是:

    [a^c~equiv~a^{c-r+r}~equiv~a^{c-r+varphi(m)+r}~equiv~a^{c+varphi(m)}~pmod m ]

    对上式做数学归纳,可得(a^c~equiv~a^{c+kvarphi(m)}~,~k~in~Z),需保证指数为正。

    于是最小的合法的指数即为(cmodvarphi(m)~+~varphi(m))

    于是有:

    [a^c~equiv~a^{c~mod~varphi(m)~+~varphi(m)}pmod m ]

    当a是一个质数的幂次时,设 (a=p^k) ,则

    [a^cequiv p^{ck}equiv p^{ck+varphi(m)}equiv p^{ck+kvarphi(m)}equiv (p^k)^{c+varphi(m)}equiv (p^k)^{cmodvarphi(m)+varphi(m)} pmod m ]

    当a时多个质数次幂的乘积时,依据唯一分解定理做数学归纳,即证正确性。证毕。

    代码
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll a,m,b;
    
    inline ll read(ll m){
    	register ll x=0,f=0;char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)){
    		x=x*10+ch-'0';
    		if(x>=m) f=1;
    		x%=m;ch=getchar();
    	}
    	return x+(f==1?m:0);
    }
    
    ll phi(ll n){
    	ll ans=n,m=sqrt(n);
    	for(ll i=2;i<=m;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;
    }
    
    ll fast_pow(ll a,ll b,ll p){
    	ll ret=1;
    	for(;b;b>>=1,a=a*a%p)
    		if(b&1) ret=ret*a%p;
    	return ret;
    }
    
    int main()
    {
        scanf("%lld%lld",&a,&m);
        b=read(phi(m));
        printf("%lld
    ",fast_pow(a,b,m));
        return 0;
    }
    

    例题

    CF17D Notepad

    思路

    这道题的范围是 (2leq aleq 10^{1000,000})(1leq nleq 10^{1000,000})(1leq pleq 10^9)

    一个(a)进制的数字的每一位有(a)种取值,但是题目要求不能有前导0,所以第一位只有(a-1)种取值。

    所以满足要求的(a)进制数有 ((a-1)a^{n-1}) 个。

    所以题目要求我们求得就是

    [(a-1)a^{n-1}mod p ]

    (但是当 (p|(a-1)a^{n-1}) 时应输出 (p) 。因为此时最后一页有0个字,相当于这一页还没写,也就不是最后一页了)

    (a,n) 很大,但是 (pleq 10^9) 。根据扩展欧拉定理,有 (a^{n-1}equiv a^{(n-1)modvarphi(p)+varphi(p)} pmod p) 。所以我们可以边读入边取模。反正 (abmod pequiv(amod p) imes (bmod p)~mod p)

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N=1000010;
    char sa[N],sn[N];
    ll p,a,n,phi,q,ans;
    int len1,len2;
    bool flag;
    
    ll power(ll x,ll k)
    {
    	ll ans=1;
    	for (;k;k>>=1,x=x*x%p)
    		if (k&1) ans=ans*x%p;
    	return ans;
    }
    
    int main()
    {
    	scanf("%s %s %lld",sa+1,sn+1,&p);
    	phi=q=p; len1=strlen(sa+1); len2=strlen(sn+1);
    	for (ll i=2;i*i<=q;i++)
    		if (!(q%i))
    		{
    			phi=phi/i*(i-1);
    			while (!(q%i)) q/=i;
    		}
    	if (q>1) phi=phi/q*(q-1);
    	for (int i=1;i<=len1;i++)
    		a=(a*10+sa[i]-48)%p;
    	for (int i=len2;i>=1;i--)  //n-1
    		if (sn[i]==48) sn[i]='9';
    		else
    		{
    			sn[i]--;
    			break;
    		}
    	for (int i=1;i<=len2;i++)
    	{
    		n=n*10+sn[i]-48;
     		if (n>=phi) flag=1;
    		n%=phi;
    	}
    	if (flag) n+=phi;
    	ans=((a-1)*power(a,n)%p+p)%p;
    	if (ans) printf("%lld",ans);
    		else printf("%lld",p);
    	return 0;
    }
    
  • 相关阅读:
    03 JVM 从入门到实战 | 简述垃圾回收算法
    02 JVM 从入门到实战 | 什么样的对象需要被 GC
    01 JVM 从入门到实战 | 什么是 JVM
    从一道面试题探究 Integer 的实现
    程序员如何写一份更好的简历
    自己动手实现分布式任务调度框架(续)
    一个excel(20M)就能干趴你的poi,你信吗?
    一个普通类就能干趴你的springboot,你信吗?
    自己动手实现springboot配置(非)中心
    自己动手实现分布式任务调度框架
  • 原文地址:https://www.cnblogs.com/jasony/p/13377358.html
Copyright © 2011-2022 走看看