思路
在信息学奥赛数论一本通里面我愣是没搞懂题解的5544、14421、1288这些数是怎么来的,在网上找了很多博客才搞懂中国剩余定理的原理。
总结一下步骤:(方程组形式为mod m意义下与a同余)求大模数M->对每个小模数M/m,求模m意义下的逆元i,那么M/mia就是满足方程的一个最小数,然后将每一个方程的最小数相加模M即可。两份代码上面是一本通的,下面是我理解之后手打AC的,希望方便各位理解。
代码
生肉版
//UVA756 Biorhythms
#include<iostream>
using namespace std;
int main(){
int p,e,i,d,T=1;
cin>>p>>e>>i>>d;
do{
int lcm=21252; //lcm(23,28,33)
int ans=(5544*p+14421*e+1288*i-d+lcm)%lcm;
if(ans==0) ans=lcm;
cout<<"Case "<<T++ <<": the next triple peak occurs in "<<ans<<" days."<<endl;
cin>>p>>e>>i>>d;
}while(p!=-1);
return 0;
} 解释版
#include<iostream>
#define debug(x) cout<<"x="<<x<<endl
#define int long long
using namespace std;
const int maxn=1e5+7;
const int mod=1e9+7;
typedef long long ll;
//ifstream mycin("in.txt");
//ofstrem mycout("out.txt");
inline void read(int &data){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
data=x*f;
}
int n;
int Exgcd(ll a,ll b,ll &x,ll &y){ //拓展欧几里得求逆元
if(!b){
x=1,y=0;
return a;
}
int gcd=Exgcd(b,a%b,y,x);
y-=a/b*x;
}
signed main(){
int p,e,i,d,T=1;
int lcm,x,y,a,b,c,ans;
lcm=23*28*33; //大模数
cin>>p>>e>>i>>d;
Exgcd(28*33,23,a,y); //求三次逆元
Exgcd(23*33,28,b,y);
Exgcd(23*28,33,c,y);
do{
ans=(28*33*a*p%lcm+23*33*b*e%lcm+23*28*c*i%lcm-d)%lcm; //相加取模
ans=(ans+lcm-1)%lcm+1; //答案“不超过”lcm,要多加一步;
cout<<"Case "<<T++ <<": the next triple peak occurs in "<<ans<<" days."<<endl;
cin>>p>>e>>i>>d;
}while(p!=-1);
return 0;
} 
京公网安备 11010502036488号