同余问题,乘法模逆元【模板】

扩展欧几里得,求一组解x,y,使得gcd(a,b)  = d = a * x + b * y

void ExGcd(int a,int b,int &d,int &x,int &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        d = a;
    }
    else
    {
        ExGcd(b,a%b,d,y,x);
        y -= x*(a/b);
    }
}

扩展欧几里得,求所有解x,y,使得c = a * x + b * y

bool ModeEqual(int a,int b,int c)   //解a*x + b*y = c;a*x ≡ c(mod b)
{
    int x,y,d,x0;
    ExGcd(a,b,d,x,y);
    if(c%d) return false;   //无解
    x0 = x * (c/d) % b;
    for(int i = 1; i < d; ++i)  //输出所有解
        printf("%d\n",(x0+i*(b/d))%b);
    return true;
}

扩展欧几里得,求a关于n的逆元a^-1,使得a * a^-1 ≡ 1(mod n)

int ModInverse(int a,int n,int &d,int &x,int &y)
{
    ExGcd(a,n,d,x,y);
	if(1 % d != 0)
		return -1;  //不存在模逆元
	int ans = x/d < 0 ? x/d + n : x/d;
	return ans;     //返回模逆元a^-1
}

扩展欧几里得,求解x,满足同余方程组x ≡ Ri(mod Ai)

int ModEquals(int N)  //解方程组x ≡ Ri(mod Ai)
{
    int a,b,d,x,y,c,A1,R1,A2,R2;
    bool flag = 1;  //标记是否有解
    scanf("%d%d",&A1,&R1);
    for(int i = 1; i < N; ++i)
    {
        scanf("%d%d",&A2,&R2);
        a = A1, b = A2, c = R2 - R1;
        ExGcd(a,b,d,x,y);
        if(c % d != 0)
            flag = 0;
        int t = b/d;
        x = (x*(c/d)%t + t) % t;
        R1 = A1 * x + R1;
        A1 = A1 * (A2 / d);
    }
    if( !flag )  R1 = -1;
    return R1;  //求出解,-1表示无解
}

扩展欧几里得,求解x,满足高次同余方程A^x ≡ B(mod C)

#define LL __int64
const int MAXN = 65535;

struct HASH
{
    int a;
    int b;
    int next;
}Hash[MAXN*2];

int flag[MAXN+66];
int top,idx;

void ins(int a,int b)
{
    int k = b & MAXN;
    if(flag[k] != idx)
    {
        flag[k] = idx;
        Hash[k].next = -1;
        Hash[k].a = a;
        Hash[k].b = b;
        return;
    }
    while(Hash[k].next != -1)
    {
        if(Hash[k].b == b)
            return;
        k = Hash[k].next;
    }
    Hash[k].next = ++top;
    Hash[top].next = -1;
    Hash[top].a = a;
    Hash[top].b = b;
}

int Find(int b)
{
    int k = b & MAXN;
    if(flag[k] != idx)
        return -1;
    while(k != -1)
    {
        if(Hash[k].b == b)
            return Hash[k].a;
        k = Hash[k].next;
    }
    return -1;
}

int GCD(int a,int b)
{
    if(b == 0)
        return a;
    return GCD(b,a%b);
}

void ExGcd(int a,int b,int &d,int &x,int &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        d = a;
    }
    else
    {
        ExGcd(b,a%b,d,y,x);
        y -= x*(a/b);
    }
}

int Inval(int a,int b,int n)
{
    int x,y,d,e;
    ExGcd(a,n,d,x,y);
    e = (LL)x*b%n;
    return e < 0 ? e + n : e;
}

int PowMod(LL a,int b,int c)
{
    LL ret = 1%c;
    a %= c;
    while(b)
    {
        if(b&1)
            ret = ret*a%c;
        a = a*a%c;
        b >>= 1;
    }
    return ret;
}

int BabyStep(int A,int B,int C) //解A^x ≡ B(mod C)
{
    top = MAXN;
    ++idx;
    LL buf = 1%C,D = buf,K;
    int d = 0,temp,i;
    for(i = 0; i <= 100; buf = buf*A%C,++i)
    {
        if(buf == B)
            return i;
    }
    while((temp = GCD(A,C)) != 1)
    {
        if(B % temp)
            return -1;
        ++d;
        C /= temp;
        B /= temp;
        D = D*A/temp%C;
    }
    int M = (int)ceil(sqrt((double)C));
    for(buf = 1%C,i = 0; i <= M; buf = buf*A%C,++i)
        ins(i,buf);
    for(i = 0,K = PowMod((LL)A,M,C); i <= M; D = D*K%C,++i)
    {
        temp = Inval((int)D,B,C);
        int w;
        if(temp >= 0 && (w = Find(temp)) != -1)
            return i * M + w + d;
    }
    return -1;  //无解
}
时间: 2024-10-11 11:09:23

同余问题,乘法模逆元【模板】的相关文章

codeforces 487C Prefix Product Sequence (模逆元+构造)

转自http://blog.csdn.net/houserabbit/article/details/41513745 题解写的真棒.. 题目链接:http://codeforces.com/problemset/problem/487/C 题目大意:构造一个1~n的排列  使得n个前缀积对n取余是一个0~n-1的排列 题目分析:好题,首先我们通过简单的分析可以得到n肯定是最后一个数,因为如果n在前面,前缀积肯定不止1个是n的倍数,也就是说对n取模至少有两个0,显然不满足排列,也就是说取模得到排

java中求余%与取模floorMod的区别

初学java的时候接触的%这个符号 百分号? 求余? 取模? 我只知道不是百分号,好像是求余,听别人那叫求模运算符,跟求余一样,于是我便信了. 思考之后开始迷糊,然后经过多次考证得到以下结论. 首先,%是求余的意思,不是求模的意思.求模不完全等于求余. 首先我们遵守公式: a = b * q + r; 这里的a是被除数,b是除数,q是商,r是余数也可以是模. q= a/b 且 |r| < |b| 于是得到: r = a – (a/b)*b; r的求值公式都是这样,那么求余和求模的区别在哪呢? 1

【转】数学与编程——求余、取模运算及其性质

声明 转自:https://blog.csdn.net/chensilly8888/article/details/42834697 此博文简短有精悍的讲述了在数学与计算机科学中求余与取模运算的区别, 在不同语言下取模的意义以及取模运算的性质 由于我觉得oi编程的话,只需要弄懂取模的性质就行了,因为编程竞赛的时候,是只用一种语言写的,自己平常打代码也就熟悉了那种语言的语法之类的. 取模运算的性质 如果a≡b(mod m),x≡y(mod m),则a+x≡b+y(mod m). 如果a≡b(mod

hdu1576-A/B-(同余定理+乘法逆元+费马小定理+快速幂)

A/B Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10383    Accepted Submission(s): 8302 Problem Description 要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1). Input 数据的第一行是一个

乘法逆元模板

1.扩展欧几里得求逆元 typedef long long ll; //ax + by = gcd(a,b) //传入固定值a,b.放回 d=gcd(a,b), x , y void extendgcd(ll a,ll b,ll &d,ll &x,ll &y) { if(b==0){d=a;x=1;y=0;return;} extendgcd(b,a%b,d,y,x); y-=x*(a/b); } //Ax=1(mod M),gcd(A,M)==1 //输入:10^18>=A

求乘法逆元模板(扩展欧几里得)

void exgcb(LL a,LL b,LL &d,LL &x,LL &y){ if(!b){d=a;x=1;y=0;return;} exgcb(b,a%b,d,y,x);y-=x*(a/b); } LL ny(LL a,LL b){ ///求a关于b的逆元(要求a,b互质) LL d,x,y; exgcb(a,b,d,x,y); return d==1?(x+b)%b:-1; }

【codevs 1200】【NOIP 2012】同余方程 拓展欧几里德求乘法逆元模板题

模板,,, #include<cstdio> using namespace std; void exgcd(long long a,long long b,long long &x,long long &y){ if (b==0) {x=1; y=0;} else {exgcd(b,a%b,x,y); int t=y; y=x-a/b*y; x=t;} } int main(){ long long a,b,x,y; scanf("%lld %lld\n"

[组合数取模-逆元计算模板] zoj 3624 Count Path Pair

思路: 正难则反 //C(M+N,M)*C(Q+M-P,Q)-C(N+M-P,N)*C(M+Q,M); 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"stack" #include"algorithm" #include"iostream" using

逆元模板

// 扩展欧几里得做法: 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define ll long long 6 using namespace std; 7 8 ll ex_gcd(ll a,ll b,ll &x,ll &y)//扩展欧几里得(扩展gcd) 9 { 10 if (a==0&&b==0)