1. 程式人生 > >中國剩餘定理 poj 1006 poj2891

中國剩餘定理 poj 1006 poj2891

Biorhythms
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 129686 Accepted: 41277

Description

Some people believe that there are three cycles in a person's life that start the day he or she is born. These three cycles are the physical, emotional, and intellectual cycles, and they have periods of lengths 23, 28, and 33 days, respectively. There is one peak in each period of a cycle. At the peak of a cycle, a person performs at his or her best in the corresponding field (physical, emotional or mental). For example, if it is the mental curve, thought processes will be sharper and concentration will be easier. 
Since the three cycles have different periods, the peaks of the three cycles generally occur at different times. We would like to determine when a triple peak occurs (the peaks of all three cycles occur in the same day) for any person. For each cycle, you will be given the number of days from the beginning of the current year at which one of its peaks (not necessarily the first) occurs. You will also be given a date expressed as the number of days from the beginning of the current year. You task is to determine the number of days from the given date to the next triple peak. The given date is not counted. For example, if the given date is 10 and the next triple peak occurs on day 12, the answer is 2, not 3. If a triple peak occurs on the given date, you should give the number of days to the next occurrence of a triple peak. 

Input

You will be given a number of cases. The input for each case consists of one line of four integers p, e, i, and d. The values p, e, and i are the number of days from the beginning of the current year at which the physical, emotional, and intellectual cycles peak, respectively. The value d is the given date and may be smaller than any of p, e, or i. All values are non-negative and at most 365, and you may assume that a triple peak will occur within 21252 days of the given date. The end of input is indicated by a line in which p = e = i = d = -1.

Output

For each test case, print the case number followed by a message indicating the number of days to the next triple peak, in the form: 

Case 1: the next triple peak occurs in 1234 days. 

Use the plural form ``days'' even if the answer is 1.

Sample Input

0 0 0 0
0 0 0 100
5 20 34 325
4 5 6 7
283 102 23 320
203 301 203 40
-1 -1 -1 -1

Sample Output

Case 1: the next triple peak occurs in 21252 days.
Case 2: the next triple peak occurs in 21152 days.
Case 3: the next triple peak occurs in 19575 days.
Case 4: the next triple peak occurs in 16994 days.
Case 5: the next triple peak occurs in 8910 days.
Case 6: the next triple peak occurs in 10789 days.

題意:

人自出生起就有體力,情感和智力三個生理週期,分別為23,28和33天

一個週期內有一天為峰值,在這一天,人在對應的方面(體力,情感或智力)表現最好

通常這三個週期的峰值不會是同一天。現在給出三個日期,分別對應於體力,情感,智力出現峰值的日期

然後再給出一個起始日期,要求從這一天開始,算出最少再過多少天后三個峰值同時出現

題解:使用中國剩餘定理

(互質的模線性方程組)

中國剩餘定理(CRT)的表述如下

設正整數兩兩互素,則同餘方程組

                             

有整數解。並且在模下的解是唯一的,解為

                               

其中,而的逆元。


逆元概念:

群G中任意一個元素a,都在G中有唯一的逆元a‘,具有性質aa'=a'a=e,其中e為群的單位元

例如:4關於1模7的乘法逆元為多少? 4X≡1 mod 7 這個方程等價於求一個X和K,滿足 4X=7K+1 其中X和K都是整數。 若ax≡1 mod f, 則稱a關於模f的乘法逆元為x。也可表示為ax≡1(mod f)。 當a與f互素時,a關於模f的乘法逆元有解。如果不互素,則無解。如果f為素數,則從1到f-1的任意數都與f互素,即在1到f-1之間都恰好有一個關於模f的乘法逆元。 例如,求5關於模14的乘法逆元: 14=5*2+4 5=4*1+1 說明5與14互素,存在5關於14的乘法逆元。 1=5-4=5-(14-5*2)=5*3-14 因此,5關於模14的乘法逆元為3。 其求法可用歐幾里得演算法,可以見我的另外一片blog,詳細推導擴充套件歐幾里得演算法 http://blog.csdn.net/summer__show_/article/details/52238225
Extended Euclid (d,f) //演算法求d關於模f的乘法逆元d-1 ,即 d* d-1 mod f = 1
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

void ex_gcd(int a1,int b,int &x,int &y)
{
    if(b==0){
        x=1,y=0;
        return ;
    }
    ex_gcd(b,a1%b,x,y);
    int temp=x;
    x=y;
    y=temp-(a1/b)*y;
}

int CRT(int a[],int m[],int n)
{
    int M=1,ans=0;
    for(int i=0;i<n;i++)
        M*=m[i];
    for(int i=0;i<n;i++){
        int x,y;
        int Mi =M/m[i];
        ex_gcd(Mi,m[i],x,y);
        ans=(ans+a[i]*x*Mi)%M;
    }
    while(ans<0)
        ans+=M;
    return ans;
}

int main()
{
    int d,cnt=1;
    int a[10],m[10];
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d%d%d",&a[0],&a[1],&a[2],&d)!=EOF)
    {
        if(a[0]==-1&&a[1]==-1&&a[2]==-1&&d==-1)
            break;

        m[0]=23;
        m[1]=28;
        m[2]=33;
        int ans=CRT(a,m,3);
        while(ans<=d)
            ans+=21252;

        ans-=d;
        printf("Case %d: the next triple peak occurs in %d days.\n",cnt++,ans);
    }
    return 0;
}


下面是中國剩餘定理的特殊情況:

不互質的模線性方程組

Strange Way to Express Integers
Time Limit: 1000MS Memory Limit: 131072K
Total Submissions: 14111 Accepted: 4564

Description

Elina is reading a book written by Rujia Liu, which introduces a strange way to express non-negative integers. The way is described as following:

Choose k different positive integers a1a2…, ak. For some non-negative m, divide it by every ai (1 ≤ i ≤ k) to find the remainder ri. If a1a2, …, ak are properly chosen, m can be determined, then the pairs (airi) can be used to express m.

“It is easy to calculate the pairs from m, ” said Elina. “But how can I find m from the pairs?”

Since Elina is new to programming, this problem is too difficult for her. Can you help her?

Input

The input contains multiple test cases. Each test cases consists of some lines.

  • Line 1: Contains the integer k.
  • Lines 2 ~ k + 1: Each contains a pair of integers airi (1 ≤ i ≤ k).

Output

Output the non-negative integer m on a separate line for each test case. If there are multiple possible values, output the smallest one. If there are no possible values, output -1.

Sample Input

2
8 7
11 9

Sample Output

31

Hint

All integers in the input and the output are non-negative and can be represented by 64-bit integral types.


題意:

就是給你n組資料

每一組資料a,b   表示    x%a==b

求這n組資料的公共的最小x的解

題解:

中國剩餘定理中的不互質的模線性方程組

由不互質的模線性方程組
x%r1=a1              1
x%r2=a2              2
x%r3=a3              3
x%r4=a4              4
......
由  1  2式子得到:
x = r1*k1 + a1
x = r2*k2 + a2
聯立:
r1*k1 + a1 =r2*k2 + a2
得到
r1*k1 + r2*k2 = a2 - a1  (其中k2的正負可變)

令g=gcd(r1,r2)

那麼上敘方程同時除以g後

r1*k1 / g + r2*k2 / g = (a2 - a1 )/ g            

由擴充套件歐幾里得可以得到k1,則有
x1 = r1*k1 + a1                         5
     x1表示1 2式子得到的r1 和 讓r2的最大公約數

(擴充套件歐幾里得演算法詳解http://blog.csdn.net/summer__show_/article/details/52238225)



因此1 2式子可以合併成
x = t*lcm(r1,r2) + x1                      
此時 x 是r1   r2  的最小公倍數,可以返回去驗證一下即可


在程式中把5式子變成x = r1*k1 + a1
即 k1=t   r1=gcd(r1,r2)   a1=x1  

然後一直迴圈求解下去

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;


#define LL long long


LL ex_gcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0){
        x=1,y=0;
        return a;
    }


    LL d=ex_gcd(b,a%b,x,y);
    LL temp=x;
    x=y;
    y=temp-(a/b)*y;
    return d;
}


int main()
{
    LL k,a1,a2,r1,r2;
    LL x,y,d;
   // freopen("in.txt","r",stdin);
    while(scanf("%I64d",&k)!=EOF)
    {
        scanf("%I64d%I64d",&a1,&r1);
        k--;
        int flag=0;
        while(k--)
        {
            scanf("%I64d%I64d",&a2,&r2);
            if(flag)
                continue;


            //擴充套件歐幾里得
            LL a=a1,b=a2;
            LL c=r2-r1;
            d=ex_gcd(a,b,x,y);//最小公約數
            if(c%d){
                flag=1;
                continue;
            }
            
            LL t=b/d;//除以d表示方程兩邊都除以d
            x=(x*(c/d)%t+t)%t;
            r1=a1*x+r1;//同上面所說的式子5
            a1=a1*(a2/d);//a1 a2最大公倍數
        }


        if(flag)
            printf("-1\n");
        else
            printf("%I64d\n",r1);
    }
    return 0;
}