扩展中国剩余定理(包含求逆元)(费马小定理)(ACM数论)

不知道的同学也可以先看看中国剩余定理:https://mp.csdn.net/postedit/99702420

有了基础就知道中国剩余定理是用来解同余方程组,可是前提条件是要除数要两两互素,但是如果题目中没有说它是互素怎么办?

以往的经验已经告诉我们,这一个算法前提条件约束不能进行的时候,便有一个扩展的算法,当然扩展中国剩余定理就是来解决他们都不一定互素的情况,它是基于扩展欧几里德算法的不知道的也可以看看上面的博客链接。

x\equiv c1(mod)m1

x\equiv c2(mod)m2

变形可以得到:   x=(m1*k1)+c1   x=(m2*k2)+c2

m1*k1=c2−c1+m2*k2

因为有些不好在这上面写,附了一张图片

如果模数是质数:

之后两边同乘以以个a的负一次即可。

加一个求a/b mod m,扩展欧几里得算法,exgcd(b,m,x,y),b的系数x就是b关于模m的逆元,即a*x(mod M)。

推导过程:

(图片写不太好见谅)

放个例题吧:http://poj.org/problem?id=2891

也算个板子。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cmath>
#include<string>
#include<map>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0)
	{
        x=1,y=0;
        return a;
    }
    ll q=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return q;
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		ll i,j,a1,c1;
		scanf("%lld %lld",&a1,&c1);
		ll x,y,a2,c2;
		bool flag=true;
		for(i=2;i<=n;i++)
		{
			scanf("%lld %lld",&a2,&c2);
			ll q=exgcd(a1,a2,x,y);
			if(labs(c2-c1)%q!=0)
			flag=false;
			else
			{
				ll t=a2/q;
	            x=((x*(c2-c1)/q)%t+t)%t;
	            c1=c1+a1*x;
	            a1=a1*(a2/q);
			}
		}
		if(!flag)
		{
			printf("-1\n");
			continue;
		}
		else
		{
			printf("%lld\n",c1);
			continue;
		}
	}
	return 0;
 } 
发布了56 篇原创文章 · 获赞 17 · 访问量 2332

猜你喜欢

转载自blog.csdn.net/weixin_43958964/article/details/100783114