EXCRT(扩展中国剩余定理)

\(excrt\) \(\text{是用来解决当模数不互质的情况下的普通}crt\text{情况的}\)

具体见P4777

事实上和\(crt\)没有什么关系

主要思想是:我们不断的合并两个同余方程,最后合并到只剩一个。

对于方程组

\(\begin{cases} x \equiv b_1\ ({\rm mod}\ a_1) \\ x\equiv b_2\ ({\rm mod}\ a_2) \\ \end{cases}\)

我们考虑合并 这两个同余方程组

我们化为

\(\begin{cases} x =a_1k_1+b_1\\ x=a_2k_2+b_2 \\ \end{cases}\)

\(\therefore a_1k_1+b_1=a_2k_2+b_2\)

\(\therefore a_1k_1-a_2k_2=b_2-b_1\)

这个可以用\(exgcd\)求出一组当\(a_1k_1-a_2k_2=(a1,a2)\)时的特解

我们将\(x/gcd(a1,a2)*(b_2-b_1)\)就可以得到原方程的一组解

那么我们可以回代解出\(a_1,b_1,a_2,b_2\)

然后

我们将\(b_2-b_1\)作为新的\(x\),\([a_1,a_2]\)作为新的模数,\(a_1k_1-a_2k_2\)作为新的余数

我们就成功的合并了两个方程

然后不停的合并下去,最后的\(x\)就是答案了

代码

/*
@Date    : 2018-10-07 11:01:36
@Author  : Adscn (1349957827@qq.com)
@Link    : https://www.cnblogs.com/LLCSBlog
*/
#ifdef FASTER
#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#endif
#include<bits/stdc++.h>
using namespace std;
#define IL inline
#define RG register
#define gi getint()
#define gc getchar()
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
typedef long long ll;
IL ll getint()
{
    RG ll xi=0;
    RG char ch=gc;
    bool f=0;
    while(ch<'0'|ch>'9')ch=='-'?f=1:f,ch=gc;
    while(ch>='0'&ch<='9')xi=(xi<<1)+(xi<<3)+ch-48,ch=gc;
    return f?-xi:xi;
}
inline ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	ll gcd=exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return gcd;
}
struct node{
	ll mod,a;
}last,now;
istream& operator >> (istream&is,node &p)
{
	cin>>p.mod>>p.a;
	return is;
}
node join(node p,node q)
{
	ll x,y;
	ll gcd=exgcd(p.mod,q.mod,x,y);
	x=(x*(__int128)(q.a-p.a)/gcd)%(q.mod/gcd);
	if((q.a-p.a)%gcd)exit(1);
	p.a=x*p.mod+p.a;
	p.mod=p.mod/gcd*q.mod;
	p.a=(p.a%p.mod+p.mod)%p.mod;
	return p;
}
int main(void)
{
    #ifdef ONLINE_JUDGE
//    File("");
    #endif
    ll n;
    cin>>n>>last;
    for(int i=2;i<=n;i++)
    {
    	cin>>now;
    	last=join(last,now);
    }
    cout<<last.a;
    return 0;
}
posted @ 2018-12-31 16:23  Adscn  阅读(446)  评论(1编辑  收藏  举报