现有两组数字,每组k个,第一组中的数字分别为:a1,a2,...,ak表示,第二组中的数字分别用b1,b2,...,bk表示。其中第二组中的数字是两两互素的。求最小的非负整数n,满足对于任意的i,n - ai能被bi整除。
中国剩余定理的裸题
题目要求的是最小的非负整数(n)满足(b_{i}|n-a_{i}(1le ile k))
将其转化成同余问题的方程组
(egin{cases}n&equiv &a_{1}(mod b_{1})\n&equiv &a_{2}(mod b_{2})\n&equiv &a_{3}(mod b_{3})\…&…&\n&equiv &a_{k}(mod b_{k})end{cases})
那么如何去求呢,这就要用到中国剩余定理了
我们设(M=prod_{i=1}^{n}b_{i}),(m_{i}=M/b_{i})
(x_{i})是方程(m_{i} imes x_{i}equiv 1(mod b_{i}))的一个解,可以由扩展欧几里得算法求得
那么答案(n)就为(sum_{i=1}^{n}a_{i} imes m_{i} imes x_{i})
为什么呢,我们来证明一下
因为(m_{i}=M/b_{i})是除了(b_{i})之外的所有(b)的积
所以(forall k e i,a_{i} imes m_{i} imes x_{i}equiv 0(mod m_{k}))
由(t_{i})是方程(m_{i} imes x_{i}equiv 1(mod b_{i})),的一个解得(a_{i} imes m_{i} imes x_{i}equiv a_{i}(mod b_{i}))
代入(n=sum_{i=1}^{n}a_{i} imes m_{i} imes x_{i}),原方程组成立。
而我们要求的是最小非负整数解,那么只需要将(n)取模(M)使其落在0~M-1的范围内即可。
这道题的坑点在于直接相乘的话会爆(long long),那么就需要用到快速乘了,思想跟快速幂一样,写起来也很简单
还有一点就是对于负数的情况要加上(M)再模(M)
Code
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
int k,a[20],b[20],M=1,ans;
void exgcd(int a,int b,int &x,int &y) //扩展欧几里得算法求线性同余方程的解
{
if (!b)x=1,y=0;
else
{
exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
}
}
int cc(int x,int y) //快速乘
{
int s=0;
x=(x%M+M)%M;
y=(y%M+M)%M; //先将负数转化为正数
while (y)
{
if (y&1)s=(s+x)%M;
x=x*2%M;
y>>=1;
}
return s;
}
signed main()
{
cin>>k;
for (int i=1;i<=k;i++)
cin>>a[i];
for (int i=1;i<=k;i++)
cin>>b[i],M*=b[i];
for (int i=1;i<=k;i++)
{
int m=M/b[i],x=0,y=0;
exgcd(m,b[i],x,y);
ans=(ans+cc(cc(a[i],m),x))%M;
}
cout<<ans<<endl;
return 0;
}