中国剩余定理 Biorhythms HDU - 1370

中国剩余定理(孙子定理):

          孙子定理是中国古代求解一次同余式组(见同余)的方法。是数论中一个重要定理。又称中国余数定理。 

                                                                                       ————参见百度;

中国剩余定理给出了以下的一元线性同余方程组

有解的判定条件,并用构造法给出了在有解情况下解的具体形式。



好吧前面都没啥用。。。。。。


例:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?

    

          解法:三人同行七十稀,五树梅花廿一支,七子团圆正半月,除百零五使得知。


解释:

     题目:有一堆东西不知道有多少,设为 N,现在有三个条件:

      N%3=2;  N%5=3; N%7=2;

     解答:   定义   lcm———“公倍数”。(非最小)

     1.   lcm(5,7)%3==1      lcm(5,7)=70;

     2.   lcm(3,5)%7==1      lcm(3,5)=15;

     3.   lcm(3,7)%5==1      lcm(3,7)=21;





而 N=70*2+15*3+21*2  ;

而3,5,7的最小公倍数为 105

最小解:N=(N+105)%105,   N=0时N+=105;


那么对于BiorhythmsHDU - 1370    题,具体解法为:

(N+d)%23==p; (N%d)%28==e;(N+d)%33==I;

  1.  lcm(23,28)%33==1    lcm()=1288;

  2.  lcm(23,33)%28==1    lcm()=14421;

  3.  lcm(28,33)%23==1    lcm()=5544;

MOD=gcd(23,28,33);


N=(1288*p+14421*e+5544*I-d+MOD)%MOD;S同样当N=0时,N+=MOD;

代码:

 

#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int kase=1;
        int p,e,i,d;
        while(scanf("%d%d%d%d",&p,&e,&i,&d))
        {
            if(p==-1&&e==-1&&i==-1&&d==-1)
                break;
            int MOD=21252;
            int n=(5544*p+14421*e+1288*i-d+MOD)%MOD;
            if(n==0)
                n=MOD;
            cout<<"Case "<<kase++<<": the next triple peak occurs in "<<n<<" days."<<endl;
        }
        if(T)
                cout<<endl;
    }
    return 0;
}

文末附上中国剩余定理的模板:

设正整数两两互素。


LL exgcd(LL a, LL b, LL &x, LL &y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	LL d = exgcd(b,a%b,y,x);
	y -= a / b *x;
	return d;
}


int china(int a[],int m[],int n) // a + tm = x ,m模(两两互素),n个方程
{  
    int M = 1;  
    int ans = 0;  
    for(int i=1; i<=n; i++)  
        M *= m[i];  
    for(int i=1; i<=n; i++)  
    {  
        int x, y;
        int Mi = M / m[i];  
        exgcd(Mi, m[i], x, y);  
        ans = (ans + Mi * x * a[i]) % M;  
    }  
    if(ans < 0) ans += M;  
    return ans;  
}


若m不是互为素数,则需要采用两两合并的方法,

         x=x1*m1+a1;    x=x2*m2+a2;

         x1*m1+a1=x2*m2+a2

         x1*m1-x2*m2=a2-a1;————(就类似于ax+by=c)

         用扩欧来解出x1的最小整数解,然后代入 x=x1*m1+a1;

         然后 得到下一个同余 的式子  y%lcm(m1,m2)=x%lcm(m1,m2);

         进行下一步的合并。

        代码:




void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(b==0)
    {
        d=a;
        x=1;
        y=0;
        return ;
    }
    ex_gcd(b,a%b,d,y,x);
    y-=a/b*x;
}
ll gcd(ll a,ll b)
{
    if(!b)  return a;
    return gcd(b,a%b);
}
ll Chinasolve(ll n)  //chushu  yushu
{
	ll x1,x2,d,x,y,dm;
	ll c,c1,c2;
	x1=a[0];c1=b[0];
	for(int i=1;i<n;i++)
    {
        x2=a[i];
        c2=b[i];
        ex_gcd(x1,x2,d,x,y);
        dm=x2/d;
        c=c2-c1;
        if(c%d)  return -1;
        x=((x*c/d)%dm+dm)%dm;
        c1=x1*x+c1;
        x1=x1*x2/d;
    }
    dg=x1;
    if(!c1)
    {
        c1=1;
        for(int i=0;i<n;i++)
        {
            c1=c1*a[i]/gcd(c1,a[i]);
        }
        dg=c1;
    }
    return c1;
}







        

    


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值