求解
\[ x \equiv \left\{\begin{aligned}a_1 \mod p_1\\a_2 \mod p_2 \\... \\a_n \mod p_n\end{aligned}\right. \]
其中 \(p_i\) 为质数
若有正整数解,输出最小的,如果没有,输出 Impossible
前置芝士:
\(exgcd\) 求乘法逆元
也就是说,求 \(x\) 使得 \(ax \equiv 1 \mod b\)
相当于求 \(ax=kb+1\)
移项
\[ ax-kb=1 \]
设 \(y=-k\)
\[ ax+by=1 \]
这玩意明显 \(exgcd\) 能搞出来
然后正式开始
中国剩余定理 \((CRT)\)
\[ x \equiv \left\{\begin{aligned}a_1 \mod p_1\\a_2 \mod p_2 \\... \\a_n \mod p_n\end{aligned}\right. \]
设 \(M=p_1*p_2*...*p_n,m_i=\frac {M}{p_i}\)
因为 \(p_i\) 都是质数,所以在 \([0,M-1]\) 范围内有且只有一个解(这个自己感性理解一下就知道了)
所以我们只要出任意一个解,然后把它对 \(M\) 取膜就好了
我们假设
\[ ans_i \equiv \left\{\begin{aligned}a_i \mod p_i \\0 \mod m_i\end{aligned}\right. \]
那么这个 \(ans_i\) 他有什么特殊之处呢?它刚好满足 \(\equiv a_i \mod p_i\) 且不会“影响”到其他的 \(a_j,p_j\)
那么答案就是 $ans=\sum_{i=1}^nans_i %M $
那么我们怎么求 $ ans_i$?
首先,\(ans_i\) 是 \(m_i\) 的倍数,所以我们设 \(ans_i=k_i*m_i\)
然后我们还要让他满足 \(\equiv a_i \mod p_i\),那么我们设 \(k_i=a_i*t_i\)
也就是说 \(ans_i=m_i*a_i*t_i\)
我们要让
\[ m_i*t_i \equiv 1 \mod p_i \]
也就是求个 \(m_i\) 在 \(\mod p_i\) 意义下的的乘法逆元嘛,\(exgcd\) 一波
然后算出每个 \(ans_i\) 加一加取个膜,没了
时间复杂度 \(O(nlog M)\)
// This code Write By chtholly_micromaker(MicroMaker)
#include <cstdio>
#include <cctype>
#define int long long
#define reg register
using namespace std;
const int MaxN=15;
template <class t> inline void rd(t &s)
{
s=0;
reg char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c))
s=(s<<3)+(s<<1)+(c^48),c=getchar();
return;
}
inline int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1,y=0;
return a;
}
reg int c=exgcd(b,a%b,y,x);
y-=a/b*x;
return c;
}
int n,mulsum;
int a[MaxN],p[MaxN];
inline int crt()
{
reg int ans=0,mi,x,y;
for(int i=1;i<=n;++i)
{
mi=mulsum/p[i];
exgcd(p[i],mi,x,y);
ans=(ans+a[i]*mi*y)%mulsum;
}
return (ans+mulsum)%mulsum;
}
inline void work()
{
mulsum=1;
rd(n);
for(int i=1;i<=n;++i)
{
rd(p[i]);rd(a[i]);
mulsum*=p[i];
}
printf("%lld\n",crt());
return;
}
signed main(void)
{
int t;rd(t);
for(int i=1;i<=t;++i)
printf("Case %lld: ",i),work();
return 0;
}