【洛谷】P3868 [TJOI2009]猜数字(中国剩余定理)

题意

解线性同余方程组

\(\left\{\begin{matrix} x-a_1\equiv 0 \pmod {b_1}\\ x-a_2\equiv 0 \pmod {b_2}\\ x-a_3\equiv 0 \pmod {b_3}\\ ...\\ x-a_k\equiv 0 \pmod {b_k} \end{matrix}\right.\)

思路

根据同余式变换法则:
如果 \(a\equiv b\pmod m\)成立,那么\(a+c\equiv b+c\pmod m\)也成立。
故可将方程组左右两边同时\(+a_i\),得

\(\left\{\begin{matrix} x\equiv a_1 \pmod {b_1}\\ x\equiv a_2 \pmod {b_2}\\ x\equiv a_3 \pmod {b_3}\\ ...\\ x\equiv a_k \pmod {b_k} \end{matrix}\right.\)

于是本题就成为了中国剩余定理的模板题。

细节

如果直接提交板子题的代码,会发现最后一个测试点一直过不去,那是因为良心出题人将数据特别大,以至于溢出了long long。。。于是本题需要运用龟速乘来防止溢出。具体使用技巧见代码。

code:

#include<cstdio>
using namespace std;
const int N=12;
#define int long long
int a[N],b[N],k,x,y,ans,M=1;
int exgcd(int &x,int &y,int a,int b)
{
	if(b==0)
	{
		x=1,y=0;
		return a;
	}
	int d=exgcd(x,y,b,a%b);
	int t=x;
	x=y,y=t-a/b*y;
	return d;
}
int gsc(int a,int b,int mod)
{
	int res=0;
	while(b)
	{
		if(b&1) res=(res+a)%mod;
		a=(a+a)%mod;
		b>>=1;
	}
	return res;
}
signed main()
{
	scanf("%lld",&k);
	for(int i=1;i<=k;i++) scanf("%lld",&a[i]);
	for(int i=1;i<=k;i++) scanf("%lld",&b[i]),M*=b[i];
	for(int i=1;i<=k;i++)
	{
		int m=M/b[i];
		x=0,y=0;
		exgcd(x,y,m,b[i]);
		x=(x%b[i]+b[i])%b[i];
		ans=(ans+gsc(gsc(a[i],m,M),x,M))%M;//这里用龟速乘就可以AC了 
	}
	printf("%lld\n",ans%M);
	return 0;
}
posted @ 2021-05-30 18:39  曙诚  阅读(62)  评论(0)    收藏  举报