• exgcd


    作用

    \(ax+by=\gcd(a,b)\) 的一个解 \(x,y\)

    裴蜀定理

    又叫贝祖定理

    \(a,b\) 是不全为零的整数,则存在整数 \(x,y\) , 使得 \(ax+by=\gcd(a,b)\)

    证明:通过解法可以证明

    解法

    \[\begin{aligned} ax+by &= \gcd(a,b) \\ ax+by &= \gcd(b,a\mod b) \\ bx+(a\mod b)y &= \gcd(b,a\mod b) \\ bx+(a-\lfloor\dfrac{a}{b}\rfloor\times b) &= \gcd(b,a\mod b) \\ bx+ay-(\lfloor\dfrac{a}{b}\rfloor\times b)y &= \gcd(b,a\mod b) \\ ay+(x-\lfloor\dfrac{a}{b}\rfloor\times y)b &= \gcd(b,a\mod b) \end{aligned} \]

    \(b=0\) 时, \(x=1,y=0\),因此可以递归求解。

    而且肯定有一组解

    同理 \(ax+by=c,\gcd(a,b)|c\) 时也是有解的

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

    当然上面这种方法是可以简单一点的

    交换操作可以在传参时解决

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

    解线性同余方程

    线性同余方程:形如 \(ax\equiv c\pmod b\) 的同余方程

    两个定理

    1. 对于方程 \(ax+by=c,\gcd(a,b)|c\) 则该方程等价于 \(ax\equiv c\pmod b\)

      也就是说,解到一个解 \(ax_0+by_0=\gcd(a,b)\) ,两边同时除以 \(\gcd(a,b)\) ,再乘 \(c\) 就找到了方程的一个解

      \(\dfrac{a\cdot c\cdot x_0}{\gcd(a,b)}+\dfrac{b\cdot c\cdot y_0}{\gcd(a,b)}=c\)

    2. \(\gcd(a,b)=1\)\(ax_0+by_0=c\) ,则该方程的任意一组解为 \(x=x_0+b*t,y=y_0-a*t\) ,其中 \(t\) 为任意整数

      根据定理 2 ,可以求出方程的最小整数解 \(x\)\(t=\dfrac{b}{\gcd(a,b)},x=(x\%t+t)\%t\)

    SDOI 2011 计算器

    对于操作 2,选用 exgcd 求解。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    inline LL Pow(LL x,LL y,LL p) {
    	register LL res=1;
    	for(;y;y>>=1,x=(x*x)%p)
    	if(y&1)res=(res*x)%p;
    	return res;
    }
    LL exgcd(LL p,LL q,LL &x,LL &y) {
    	if(!q)return x=1,y=0,p;
    	register LL gcd=exgcd(q,p%q,y,x);
    	return y-=p/q*x,gcd;
    }
    const int Su=100007;
    struct HASH {
    	int cnt,lst[Su],nxt[Su],id[Su];
    	LL vl[Su];
    	inline void Clear() { memset(lst,0,sizeof(lst)),cnt=0; }
    	inline void Ins(LL x,int p) {
    		vl[++cnt]=x,id[cnt]=p,x%=Su;
    		nxt[cnt]=lst[x],lst[x]=cnt;
    	}
    	inline int Find(LL x) {
    		for(int i=lst[x%Su];i;i=nxt[i])
    			if(vl[i]==x)return id[i];
    		return -1;
    	}
    }hs;
    inline LL BSGS(LL x,LL y,LL p) {
    	if(x%p==0)return -1;
    	x%=p,y%=p;
    	if(y==1)return 0;
        register int z=sqrt(p)+1;
        register LL sx=y,sy;
        hs.Clear();
        for(int i=0;i<z;++i,sx=sx*x%p)
    		hs.Ins(sx,i);
        sy=Pow(x,z,p),sx=1;
        for(int i=1,k;i<=z;++i) {
        	sx=sx*sy%p,k=hs.Find(sx);
        	if(k!=-1)return 1LL*i*z-1LL*k;
    	}
        return -1;
    }
    int T,K;
    int main() {
    	scanf("%d%d",&T,&K);
    	for(LL x,y,p,tmp,u,v;T--;) {
    		scanf("%lld%lld%lld",&x,&y,&p);
    		if(K==1)printf("%lld\n",Pow(x,y,p));
    		else if(K==2) {
    			tmp=exgcd(x,p,u,v);
    			if(y%tmp)puts("Orz, I cannot find x!");
    			else u*=y/tmp,v=p/tmp,printf("%lld\n",(u%v+v)%v);
    		} else {
    			tmp=BSGS(x%p,y%p,p);
    			if(tmp<0)puts("Orz, I cannot find x!");
    			else printf("%lld\n",tmp);
    		}
    	}
    }
    
  • 相关阅读:
    全栈项目|小书架|服务器端-NodeJS+Koa2实现首页图书列表接口
    全栈项目|小书架|微信小程序-首页水平轮播实现
    全栈项目|小书架|微信小程序-登录及token鉴权
    全栈项目|小书架|微信小程序-项目结构设计分包
    Python学习第123天(Django回头看:模板控制语句、filter、simple_tag)
    Python学习第122天(Django回头看:视图函数、redirect、模板变量、过滤器)
    Python学习第121天(Django2的include使用)
    Python学习第120天(Django1和2之间的区别)
    Python学习第119天(练习)
    Python学习第119天(暂停)
  • 原文地址:https://www.cnblogs.com/KonjakLAF/p/14585706.html
Copyright © 2020-2023  润新知