中国剩余定理 模板 P3868 [TJOI2009]猜数字

2019-04-14 17:22发布

中国剩余定理预备知识:扩展欧几里得
扩展欧几里得:
用来计算最小公倍数,及其求解线性方程和同余方程
中国剩余定理:
首先假如我们求出这样三个数
k1,k2,k3
k1,k2,k3
,满足k1模3余1且是5和7的倍数,k2模5余1且是3,7的倍数,k3模7余1且是3和5的倍数,那么容易意会得到,
k1∗2+k2∗3+k3∗2
k1∗2+k2∗3+k3∗2
一定会是一个满足题目条件的数。而题目的通解可表示为这个数每次都加上3,5,7的最小公倍数
首先我们求出3,5,7的lcm=105
然后我们令:
x1=105/3=35
x1=105/3=35
,
x2=105/5=21
x2=105/5=21
,
x3=105/7=15
x3=105/7=15 然后我们求解以下方程:
a∗x1%3=1
a∗x1%3=1
,
b∗x2%5=1
b∗x2%5=1
,
c∗x3%7=1
c∗x3%7=1 啊呀这个格式的式子好眼熟。。。那么就愉快地用扩展欧几里德求出来吧!
a=2,b=1,c=1。
答案就是:
ans=(a∗x1∗2+b∗x2∗3+c∗x3∗2)%lcm=23 注意:这是我从博客中写的,不一定编译通过,但是思路不会有问题,代码有瑕疵。(请不要复制粘贴) #include #include #include #include #include #include using namespace std; int n; int m[105]; int p[105]; int exgcd(int a,int b,int &x,int &y){//扩展欧几里得 if(!b){ x = 1; y = 0; return a; } int re = exgcd(b,a%b,x,y); int tmp = x; x = y; y = tmp-(a/b)*y; return re; } int china(){ int sum = 0; int lcm = 1; int x,y; for(int i=1;i<=n;i++){ lcm = (lcm*m[i]); } for(int i=1;i<=n;i++){ int tp = lcm/m[i]; int d = exgcd(tp,m[i],x,y); x = (x%m[i]+m[i])%m[i]; sum = (sum+tp*p[i]*x)%lcm; } return (sum+lcm)%lcm; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&p[i]); } for(int i=1;i<=n;i++){ scanf("%d",&m[i]); } printf("%d ",china()); }