我好菜啊
中国剩余定理
我愿意称它为动动定理
有方程组:
\[\begin{cases}x\equiv a_1 (mod\ p_1)\\x\equiv a_2 (mod\ p_2)\\……\\x\equiv a_n (mod\ p_n)\end{cases}\]
其中对于\(i\in[1,n],p_i\)两两互质
求解:
定义\(M=\prod\limits_{i=1}^{n}p_i,M_i=\frac{\prod\limits_{j=1}^{n}p_j}{p_i}\)
则方程组的解为\(\sum\limits_{i=1}^{n}a_i*M_i*p_i^{-1}\)
证明:
观察\(a_i*M_i*p_i^{-1}\)
对于\(j\ne i\)来说,由于\(M_i\)是\(p_j\)的倍数,所以\(\equiv 0(mod\ p_j)\)
对于\(i\)来说,由于\(p_i\)两两互质,所以\(M_i\)中不含\(p_i\)的倍数,且\(a_i*M_i*p_i^{-1}\equiv a_i(mod\ p_i)\)
code
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define eps (1e-8)
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=110;
int n,m=1,x,y,ret;
int a[N],p[N];
inline void exgcd(int &x,int &y,int a,int b)
{
if(!b){x=1,y=0;return;}
exgcd(y,x,b,a%b);
y-=a/b*x;
}
inline void crt()
{
for(int i=1;i<=n;++i)
{
exgcd(x,y,m/p[i],p[i]);
ret=(ret+m/p[i]*x%m*a[i]%m)%m;
}
}
inline void main()
{
n=read();
for(int i=1;i<=n;++i)
{
p[i]=read();
a[i]=read()%p[i];
m*=p[i];
}
crt();
printf("%lld\n",(ret%m+m)%m);
}
}
signed main()
{
red::main();
return 0;
}
拓展中国剩余定理
有方程组:
\[\begin{cases}x\equiv a_1 (mod\ p_1)\\x\equiv a_2 (mod\ p_2)\\……\\x\equiv a_n (mod\ p_n)\end{cases}\]
还是它!不过我们这次不保证\(p_i\)两两互质
我们选择关闭本题
求解:
其实我们可以数学归纳,假设我们已经求解出了前\(k-1\)个方程组的答案
重新定义\(M=LCM_{i=1}^{k-1}p_i\),则前\(k-1\)个方程的解为\(x+i*M(i\in Z)\)
考虑与第\(k\)个方程合并,使得\(x+t*M\equiv a_k(mod\ p_k)\)
去掉模数+移项得到\(t*M+y*p_k\equiv a_k-x\)
我们用\(exgcd\)求出\(t\),则前\(k\)个方程组的解为\(x+t*M\)
注意\(exgcd\)无解的情况
code
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define eps (1e-8)
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=1e5+10;
int n,m,ret;
int a[N],p[N];
int x,y,g;
inline void exgcd(int &x,int &y,int &g,int a,int b)
{
if(!b){x=1,y=0,g=a;return;}
exgcd(y,x,g,b,a%b);
y-=a/b*x;
}
inline int slow(int x,int k,int p)
{
int ret=0;
while(k)
{
if(k&1) ret=(ret+x)%p;
x=(x+x)%p;
k>>=1;
}
return ret;
}
inline void excrt()
{
m=p[1],ret=a[1];
for(int i=2;i<=n;++i)
{
int c=((a[i]-ret)%p[i]+p[i])%p[i];
exgcd(x,y,g,m,p[i]);
if(c%g);//无解
x=slow(x,c/g,p[i]);
ret+=x*m;
m*=p[i]/g;
ret=(ret+m)%m;
}
}
inline void main()
{
n=read();
for(int i=1;i<=n;++i) p[i]=read(),a[i]=read()%p[i];
excrt();
printf("%lld\n",(ret%m+m)%m);
}
}
signed main()
{
red::main();
return 0;
}