【洛谷】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;
}