题目描述
现有两组数字,每组k个,第一组中的数字分别为:a1,a2,…,ak表示,第二组中的数字分别用b1,b2,…,bk表示。其中第二组中的数字是两两互素的。求最小的非负整数n,满足对于任意的i,n - ai能被bi整除。
输入格式:
输入数据的第一行是一个整数k,(1 ≤ k ≤ 10)。接下来有两行,第一行是:a1,a2,…,ak,第二行是b1,b2,…,bk
输出格式:
输出所求的整数n。
说明
所有数据中,第一组数字的绝对值不超过 1 0 9 10^{9} 109(可能为负数),第二组数字均为不超过6000的正整数,且第二组里所有数的乘积不超过 1 0 18 10^{18} 1018
题目分析
由题意知
{
b
1
∣
(
n
−
a
1
)
b
2
∣
(
n
−
a
2
)
.
.
.
b
k
∣
(
n
−
a
k
)
\begin{cases} b_1\mid (n-a_1) \quad \\ b_2 \mid (n-a_2) \quad \\ ...\quad \\ b_k\mid (n-a_k)\quad \\ \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧b1∣(n−a1)b2∣(n−a2)...bk∣(n−ak)
变换成同余方程组得
{
n
−
a
1
≡
0
(
m
o
d
  
b
1
)
n
−
a
2
≡
0
(
m
o
d
  
b
2
)
.
.
.
n
−
a
k
≡
0
(
m
o
d
  
b
k
)
\begin{cases} n-a_1\equiv 0(\mod b_1)\quad \\ n-a_2\equiv 0(\mod b_2) \quad \\ ...\quad \\ n-a_k\equiv 0(\mod b_k)\quad \\ \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧n−a1≡0(modb1)n−a2≡0(modb2)...n−ak≡0(modbk)
根据同余式变换法则
如果有
a
≡
b
(
m
o
d
  
m
)
a\equiv b(\mod m)
a≡b(modm)
则
a
+
c
≡
b
+
c
(
m
o
d
  
m
)
a+c\equiv b+c(\mod m)
a+c≡b+c(modm)成立
将上述方程组变形得
{
n
≡
a
1
(
m
o
d
  
b
1
)
n
≡
a
2
(
m
o
d
  
b
2
)
.
.
.
n
≡
a
k
(
m
o
d
  
b
k
)
\begin{cases} n\equiv a_1(\mod b_1)\quad \\ n\equiv a_2(\mod b_2)\quad \\ ...\quad \\ n\equiv a_k(\mod b_k)\quad \\ \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧n≡a1(modb1)n≡a2(modb2)...n≡ak(modbk)
到这里就是裸得中国剩余定理了
不过要注意计算前要将所有
a
[
i
]
=
(
a
[
i
]
m
o
d
  
b
[
i
]
+
b
[
i
]
)
m
o
d
  
b
[
i
]
;
a[i]=(a[i]\mod b[i]+b[i])\mod b[i];
a[i]=(a[i]modb[i]+b[i])modb[i];
另外这题出题人用(sang)心(xin)良(bing)苦(kuang)
要用快速乘,不然最后一个点爆long long
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;
lt read()
{
lt f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
int k;
lt a[20],b[20];
lt qmul(lt a,lt b,lt mod)
{
lt ans=0;
while(b>0)
{
if(b&1) ans=(ans+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return ans;
}
void exgcd(lt a,lt b,lt &x,lt &y)
{
if(b==0){ x=1; y=0; return;}
exgcd(b,a%b,x,y);
int tp=x;
x=y; y=tp-a/b*y;
}
lt china()
{
lt ans=0,lcm=1,x,y;
for(int i=1;i<=k;++i) lcm*=b[i];
for(int i=1;i<=k;++i)
{
lt tp=lcm/b[i];
exgcd(tp,b[i],x,y);
x=(x%b[i]+b[i])%b[i];
ans=(ans+qmul(qmul(tp,x,lcm),a[i],lcm))%lcm;
}
return (ans+lcm)%lcm;
}
int main()
{
k=read();
for(int i=1;i<=k;++i) a[i]=read();
for(int i=1;i<=k;++i) b[i]=read();
for(int i=1;i<=k;i++) a[i]=(a[i]%b[i]+b[i])%b[i];
cout<<china();
return 0;
}