POJ 1006 Biorhythms (中国剩余定理)

在POJ上有译文(原文右上角),选择语言:简体中文


求解同余方程组:
x=ai(mod mi) i=1~r, m1,m2,...,mr互质
利用中国剩余定理
令M=m1*m2*...*mr,Mi=M/mi
因为mi两两互质,所以(Mi,mi)=1
令Mi*yi=1(mod mi)的解为yi,即Mi模mi的逆元
则方程的解为:
(a1*M1*y1+a2*M2*y2+...+ar*Mr*yr)%M

 

方法一:用扩展欧几里德求逆元

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;
const int M=21252;
int a[3],m[3]={23,28,33};
int sp,se,si,d;
int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    int d=exgcd(b,a%b,x,y);
    int tmp=x;
    x=y;
    y=tmp-a/b*y;
    return d;
}
int main()
{
    int cases=0,ans;
    int ni[3],Mi[3],x,y;
    //因为mi是固定的,所以可以先将对应的逆元用扩展欧几里德求出来
    for(int i=0;i<3;i++){
        Mi[i]=M/m[i];
        exgcd(Mi[i],m[i],x,y);
        ni[i]=x;
    }
    while(scanf("%d%d%d%d",&sp,&se,&si,&d)!=EOF){
        if(sp==-1)
            break;
        a[0]=sp;a[1]=se;a[2]=si;
        ans=0;
        for(int i=0;i<3;i++){
            ans=(ans+(a[i]*Mi[i]%M)*ni[i]%M)%M;
            ans=(ans+M)%M;
        }
        if(ans<=d){
            ans=ans+M-d;
        }
        else
            ans=ans-d;
        printf("Case %d: the next triple peak occurs in %d days.\n",++cases,ans);

    }
    return 0;
}
View Code

 

方法二:枚举求Mi*yi

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int M=21252;
int m[3]= {23,28,33};
int a[3];
int sp,se,si,d;
int Mii[3],Mi[3];
int value;

//求最大公约数,最小公倍数则两数相乘除以它们的最大公约数
int gcd(int a,int b) {
    if(b==0)
        return a;
    else
        return gcd(b,a%b);
}
int main() {
    int cases=0;
    Mii[0]=Mi[0]=m[1]*m[2];
    Mii[1]=Mi[1]=m[0]*m[2];
    Mii[2]=Mi[2]=m[0]*m[1];
    //枚举求Mi*yi
    for(; Mii[0]%m[0]!=1; Mii[0]+=Mi[0]) {
    }
    for(; Mii[1]%m[1]!=1; Mii[1]+=Mi[1]) {
    }
    for(; Mii[2]%m[2]!=1; Mii[2]+=Mi[2]) {
    }
    while(scanf("%d%d%d%d",&sp,&se,&si,&d)!=EOF) {
        if(sp==-1)
            break;
        a[0]=sp;
        a[1]=se;
        a[2]=si;
        value=((Mii[0]*a[0]+Mii[1]*a[1]+Mii[2]*a[2])%M+M)%M;
        int ans;
        if(value<=d) {
            ans=value+M-d;
        } else
            ans=value-d;
        printf("Case %d: the next triple peak occurs in %d days.\n",++cases,ans);


    }
    return 0;
}
View Code

 

posted @ 2014-02-19 17:26  辰曦~文若  阅读(200)  评论(0编辑  收藏  举报