您的位置:首页 > 其它

中国剩余定理两个模板

2017-07-18 15:32 381 查看
1:普通剩余定理,要求模数互质:

(三个心理周期那题)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define LL long long

using namespace std;
int a[4],r[4];
int p,e,i,d;
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return a;
}
int x1,y1;
int gc=exgcd(b,a%b,x1,y1);
if(a*b<0){
x=-y1;
y=-(x1-a/b*y1);
}
else{
x=y1;
y=x1-a/b*y1;
}
return gc;
}
void solve(){
int M=r[1]*r[2]*r[3];
int ans=0;
for(int i=1;i<=3;i++){
int x,y;
int Mi=M/r[i];
int gc=exgcd(Mi,r[i],x,y);
//cout<<a[i]<<endl;
ans=(ans+Mi*x*a[i])%M;
}
if(ans<0) ans+=M;
if(ans<=d) ans+=21252;
printf("%d days.\n",ans-d);
//cout<<ans<<endl;
}
int main()
{
int cas=1;
int t;
scanf("%d",&t);
while(scanf("%d %d %d %d",&p,&e,&i,&d)){
if(p==-1) break;
a[1]=p,a[2]=e,a[3]=i;
r[1]=23,r[2]=28,r[3]=33;
printf("Case %d: the next triple peak occurs in ",cas++);
solve();

}
return 0;
}

2:模数不互质,此时要采用两两合并的思想,假设要合并如下两个方程

 

     


 

那么得到

 

      


 

在利用扩展欧几里得算法解出

的最小正整数解,再带入

 

      


 

得到

后合并为一个方程的结果为

 

       


 

这样一直合并下去,最终可以求得同余方程组的解。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define siz 101
#define LL long long int
using namespace std;
LL p[siz],n;
bool f[siz];
LL a[siz],r[siz];
LL exgcd(LL a,LL b,LL &x,LL &y){
if(b==0){
x=1;
y=0;
return a;
}
LL x1,y1;
LL d=exgcd(b,a%b,x1,y1);
if(a*b<0){
x=-y1;
y=-(x1-a/b*y1);
}
else{
x=y1;
y=x1-a/b*y1;
}
return d;
}
void solve(int t){
LL b,a1,c1;
a1=a[0];c1=r[0];
int flag=1;
for(LL i=1;i<n;i++){
LL c=r[i]-c1;
LL m=a1;
LL x,y;
LL d=exgcd(m,a[i],x,y);
if(c%d!=0){
flag=0;
}
LL t=a[i]/d;
x=((x*(c/d))%t+t)%t;
c1=m*x+c1;
a1=m*(a[i]/d);
}
if(!flag) cout<<"Case "<<t<<": "<<-1<<endl;
else{
if(c1==0) c1=a1;
cout<<"Case "<<t<<": "<<c1<<endl;
}
}
int main()
{
//LL n;
int t,tx=0;
scanf("%d",&t);
while(t--){
//scanf("%lld",&n);
cin>>n;
for(int i=0;i<n;i++){
//scanf("%lld %lld",&a[i],&r[i]);
cin>>a[i];
}
for(int i=0;i<n;i++){
cin>>r[i];
}
solve(++tx);
}

//cin>>n;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: