T186362 一元一次同余方程组 题解

注意到这个题不是中国剩余定理。

首先考虑化为中国剩余定理的形式,那么如何才可以消去左边的a呢?

考虑后,我们可以发现如下结论:如果$b$不能被$gcd(a,c)$整除,那么原方程就没有解。因为此时左边一定有一个质因子但右边没有

而如果可以整除,就可以令原式全部除以$gcd(a,c)$,因为$atx+bty=tc$和$ax+by=c$的解集是完全相同的

于是a和c就互质了。

这个时候就可以在等式两边同时乘$a$的逆元。

于是原式的形式就变为了中国剩余定理的标准形式。

但是还不够,因为我们依然无法保证所以的$c$两两互质

经过思考,继续使用中国剩余定理已经不可能了,因为原来的互质的性质被破坏后,大多数结论都会发生改变。

这个时候我们考虑通过数学归纳法求解。


假设我们已经得到了前k-1个柿子的通解为\(t+xlcm(x\in Z)\),其中\(t\)为一个特解
然后,第k个柿子提供的限制条件为
\(t+xlcm\equiv b_i(mod\ c_i)\)
这是一个线性同余方程,转化为不定方程后移项,得
\(xlcm+yc_i=b_i-t\)
利用exgcd求出新的通解即可。
这个题也是模板EXCRT的强化版。
注意一个问题,求逆元时要使用EXGCD,因为模数不是质数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
inline int r()
{
	int s=0,k=1;char c=getchar();
	while(!isdigit(c))
	{
		if(c=='-')k=-1;
		c=getchar();
	}
	while(isdigit(c))
	{
		s=s*10+c-'0';
		c=getchar();
	}
	return s*k;
}
int n,a[1000001],b[1000001],c[1000001],x,y;
int exgcd(int a,int b)
{
	if(!b)
	{
		x=1;y=0;
		return a;
	}
	int g=exgcd(b,a%b),tmp=x;
	x=y;
	y=tmp-y*(a/b);
	return g;
}
int pw(int t,int p,int mod)//t^p % mod
{
	int base=t,ans=1;
	while(p)
	{
		if(p&1)
		{
			ans*=base;
			ans%=mod;
		}
		base*=base;
		base%=mod;
		p>>=1;
	}
	return ans;
}
int mul(int a,int b,int mod)
{
    int ans=0;
    while(b>0)
    {
        if(b&1)ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}
int ny(int xx,int mod)
{
	int g=exgcd(xx,mod);
	return (x%mod+mod)%mod;
}
signed main()
{
	n=r();
	for(int i=1;i<=n;i++)
	{
		a[i]=r();b[i]=r();c[i]=r();
		int g=exgcd(a[i],c[i]);
		if(b[i]%g)
		{
			cout<<"nO sOLuTiOn"<<endl;
			return 0;
		}
		a[i]/=g;b[i]/=g;c[i]/=g;
		b[i]*=ny(a[i],c[i]);
//		cout<<"逆元是"<<ny(a[i],c[i]);
		b[i]%=c[i];
//		cout<<b[i]<<" "<<c[i]<<endl;
	}
	exgcd(1,c[1]);
	x*=b[1];x=(x%c[1]+c[1])%c[1];
	int now=x,lcm=c[1];
	for(int i=2;i<=n;i++)
	{
		int aa=lcm,bb=c[i],cc=b[i]-now;
		int g=exgcd(aa,bb);
//		cout<<"aa/lcm:"<<aa<<" bb:"<<bb<<" cc:"<<cc<<" g:"<<g<<" now:"<<now<<endl;
		if(cc%g)
		{
			cout<<"nO sOLuTiOn"<<endl;
			return 0;
		}
		bb/=g;
		cc/=g;
		x=(x%bb+bb)%bb;cc=(cc%bb+bb)%bb;
		x=mul(x,cc,bb);
		x=(x%bb+bb)%bb;
		now=now+x*lcm;
		lcm=c[i]/exgcd(c[i],lcm)*lcm;//
		now=(now%lcm+lcm)%lcm;
	}
	cout<<now<<endl;
}
posted @ 2021-07-16 21:05  lei_yu  阅读(292)  评论(0编辑  收藏  举报