POJ1006生理周期----【模板】CRT中国剩余定理即孙子定理即求解一次同余方程


#有时间要弄懂的详细过程:

http://m.blog.csdn.net/article/details?id=52290361


#待做题:

http://blog.csdn.net/acdreamers/article/details/8050018


模板:

#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long ll;
int a[4],m[4];
void exgcd(int a,int b,int& x,int& y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return; //表示程序退出,但是没有返回值
    }
    exgcd(b,a%b,x,y);
    int temp = x;
    x = y;
    y = temp - (a/b) * y;
}

int CRT(int a[],int m[],int k)//a[]为余数,b[]为除数,k为给定一次线性同余式的个数即系数对的个数
{
    int mm=1;//mm为余数的公倍数
    int result=0;
    for(int i=0;i<k;i++)
        mm*=m[i];
    for(int i=0;i<k;i++)
    {
        int x,y;
        int mi=mm/m[i];
        exgcd(mi,m[i],x,y);//求逆元x
        result=(result+ mi*x*a[i])%mm;
    }
    return (result%mm+mm)%mm;//落在(0, mm)之间,防止result为负数
    /*
    即:
    if(result<0)
        return result+mm;
    return result;
    */
}




Chinese remainder theorem(CRT):

中国剩余定理是求解一次线性同余方程组的方法。

中国剩余定理: 
假设整数m1,m2, … ,mn两两互素,则同余方程组 
这里写图片描述 
有整数解。 
这里写图片描述 是m1,m2,m3…mn的乘积,并设 这里写图片描述是除了mi以外的n-1个整数的乘积。 
这里写图片描述是Mi模mi的逆元(数论中的倒数)。

那么在模M下的解是唯一的。

这里写图片描述

应用举例:

  1. //一个数被3除余1,被4除余2,被5除余4,这个数最小是几?   
  2.    //题中3、4、5三个数两两互质。   
  3.    //则〔4,5〕=20;〔3,5〕=15;〔3,4〕=12;〔3,4,5〕=60。   
  4.    //为了使20被3除余1,用20×2=40;   
  5.    //使15被4除余1,用15×3=45;   
  6.    //使12被5除余1,用12×3=36。   
  7.    //然后,40×1+45×2+36×4=274,   
  8.    //因为,274>60,所以,274%60=34,就是所求的数。  

----------------------------------------------------------------------------------------------------------------------------------------------------------


•以「韩信点兵」为例,假设x是那个未知数,而除3,5,7后的余数分别为r1,r2,r3。因此有 

x≡r1(mod 3) 
 
x≡r2(mod 5) 
 
x≡r3(mod 7) 



解:(15*?)%7=1

(35*??)%3=1

(21*???)%5=1


X=(?*7+??*3+???*5)%(3*5*7)



方法一:套模板

#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long ll;
int a[4],m[4];
void exgcd(int a,int b,int& x,int& y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return; //表示程序退出,但是没有返回值
    }
    exgcd(b,a%b,x,y);
    int temp = x;
    x = y;
    y = temp - (a/b) * y;
}

int CRT(int a[],int m[],int k)//a[]为余数,b[]为除数,k为给定一次线性同余式的个数即系数对的个数
{
    int mm=1;//mm为余数的公倍数
    int result=0;
    for(int i=0;i<k;i++)
        mm*=m[i];
    for(int i=0;i<k;i++)
    {
        int x,y;
        int mi=mm/m[i];
        exgcd(mi,m[i],x,y);//求逆元x
        result=(result+ mi*x*a[i])%mm;
    }
    return (result%mm+mm)%mm;//落在(0, mm)之间,防止result为负数
    /*
    即:
    if(result<0)
        return result+mm;
    return result;
    */
}

int main()
{
    int p, e, i, d, t = 1;
    while(cin>>p>>e>>i>>d)
    {
        if(p == -1 && e == -1 && i == -1 && d == -1)
            break;
        while(p>23)
            p-=23;
       while(e>28)
            e-=28;
        while(i>33)
            i-=33;
        a[0] = p;
        a[1] = e;
        a[2] = i;
        m[0] = 23;
        m[1] = 28;
        m[2] = 33;
        int ans = CRT(a, m, 3);
        if(ans <= d)
            ans += 21252;
        cout<<"Case "<<t++<<": the next triple peak occurs in "<<ans - d<<" days."<<endl;
    }
    return 0;
}


方法二:数学方法


#include<iostream>  
using namespace std;  
  
int main(void)  
{  
    int p,e,i,d;  
    int time=1;  
    while(cin>>p>>e>>i>>d)  
    {  
        if(p==-1 && e==-1 && i==-1 && d==-1)  
            break;  
  
        int lcm=21252;  // lcm(23,28,33)  
        int n=(5544*p+14421*e+1288*i-d+21252)%21252;  
        if(n==0)  
            n=21252;  
        cout<<"Case "<<time++<<": the next triple peak occurs in "<<n<<" days."<<endl;  
    }  
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值