思路

在信息学奥赛数论一本通里面我愣是没搞懂题解的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;
}