题目大意: 求下面这个方程组的最小正整数解。
{
(
n
−
a
1
)
∣
b
1
(
n
−
a
2
)
∣
b
2
⋮
(
n
−
a
k
)
∣
b
k
\begin{cases} (n-a_1) | b_1\\ (n-a_2) | b_2\\ ~~\vdots\\ (n-a_k) | b_k\\ \end{cases}
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧(n−a1)∣b1(n−a2)∣b2 ⋮(n−ak)∣bk
题解
我们把柿子变化一下:
{
(
n
−
a
1
)
∣
b
1
(
n
−
a
2
)
∣
b
2
⋮
(
n
−
a
k
)
∣
b
k
⇒
{
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
)
⇒
{
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-a_1) | b_1\\ (n-a_2) | b_2\\ ~~\vdots\\ (n-a_k) | b_k\\ \end{cases} \Rightarrow \begin{cases} n-a_1 \equiv 0 \pmod {b_1}\\ n-a_2 \equiv 0 \pmod {b_2}\\ ~~\vdots\\ n-a_k \equiv 0 \pmod {b_k}\\ \end{cases} \Rightarrow \begin{cases} n \equiv a_1 \pmod {b_1}\\ n \equiv a_2 \pmod {b_2}\\ ~~\vdots\\ n \equiv a_k \pmod {b_k}\\ \end{cases}
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧(n−a1)∣b1(n−a2)∣b2 ⋮(n−ak)∣bk⇒⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧n−a1≡0(modb1)n−a2≡0(modb2) ⋮n−ak≡0(modbk)⇒⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧n≡a1(modb1)n≡a2(modb2) ⋮n≡ak(modbk)
然后就是个中国剩余定理裸题了。
但是题目里面说 ∏ b i ≤ 1 0 18 \prod b_i \leq 10^{18} ∏bi≤1018,这意味着中间的运算依然可能爆 l o n g l o n g long~long long long,所以要用快速乘。
以及, b i b_i bi 不一定是个质数,所以求逆元需要用 exgcd。
代码如下:
#include <cstdio>
#include <cstring>
#define ll long long
int n;
ll a[11],b[11],t[11],M=1,ans=0;
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0){x=1,y=0;return;}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
ll inv(ll a,ll mod)
{
ll x,y;
exgcd(a,mod,x,y);
return (x+mod)%mod;
}
ll ksc(ll x,ll y)
{
ll re=0,tot=x;
while(y)
{
if(y&1ll)re=(re+tot)%M;
tot=(tot+tot)%M;
y>>=1ll;
}
return re;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
scanf("%lld",&b[i]),a[i]=(a[i]%b[i]+b[i])%b[i],M*=b[i];
for(int i=1;i<=n;i++)
t[i]=inv(M/b[i],b[i]);
for(int i=1;i<=n;i++)
ans=(ans+ksc(ksc(a[i],t[i]),M/b[i]))%M;
printf("%lld",ans);
}