Poj 1006 生理周期(中国剩余定理)


一、Description

人生来就有三个生理周期,分别为体力、感情和智力周期,它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。在高峰这天,人会在相应的方面表现出色。例如,智力周期的高峰,人会思维敏捷,精力容易高度集中。因为三个周期的周长不同,所以通常三个周期的高峰不会落在同一天。对于每个人,我们想知道何时三个高峰落在同一天。对于每个周期,我们会给出从当前年份的第一天开始,到出现高峰的天数(不一定是第一次高峰出现的时间)。你的任务是给定一个从当年第一天开始数的天数,输出从给定时间开始(不包括给定时间)下一次三个高峰落在同一天的时间(距给定时间的天数)。例如:给定时间为10,下次出现三个高峰同天的时间是12,则输出2(注意这里不是3)。

Input

输入四个整数:p, e, i和d。 p, e, i分别表示体力、情感和智力高峰出现的时间(时间从当年的第一天开始计算)。d 是给定的时间,可能小于p, e, 或 i。 所有给定时间是非负的并且小于365, 所求的时间小于21252。
当p = e = i = d = -1时,输入数据结束。

Output

从给定时间起,下一次三个高峰同天的时间(距离给定时间的天数)。

二、问题分析
        发现这道题有翻译的时候,长舒了一口气。但没想到中文意思都这么坑爹,唉,硬着头皮看了几遍没思路,后来看了discuss发现是中国余数定理(其实我根本不懂神马中国余数定理)。这就是这道题的全部了,下面详细了解一下这个定理。
中国古代求解一次同余式组(见同余)的方法。是数论中一个重要定理。又称中国剩余定理。
设m1,m2,…mk是两两互素的正整数,则对任意b1,b2,…,bk,同余方程组
x mod m1=b1 mod m1,
x mod m2=b2 mod m2,

x mod mk=bk mod mk, 其解为:
 x=(M1’M1b1+M2’M2b2+…+M’kMkbk )mod m
m=m1m2…mk,   
Mi=m/mi  
MiMi’ mod mi=1 显然(Mi,mi)=1

解题思路:

令某数为M,令素数为A,B,C,D,…,Z,已知M/A余a,M/B余b,M/C余c,M/D余d,…,M/Z余z。求M=?

因为A,B,C,D,…,Z为不同的素数,故,B*C*D*…*Z不可能被A整除,有等差数列(B*C*D*…*Z)+(B*C*D*…*Z)N中取A个连续项,这A个连续项分别除以A的余数必然存在0,1,2,3,…,A-1,所以,从这A个连续项中能寻找到除以A余1的数。再用除以A余1的这个数*a其积必然除以A余a,这个除以A余a的数,为能够被素数B*C*D*…*Z整除的数,为第一个数;

再按同样的道理,从A*C*D*…*Z的倍数中寻找除以B余b的数,该数具备被素数A,C,D,…,Z整除的特性,为第二个数;

因为,第一个数除以A余a,第二个数能被素数A,C,D,…,Z整除,即能被A整除,所以,第一个数+第二个数之和,仍然保持除以A余a;

同理,第二个数除以B余b,因第一个数能被B整除,所以,第二个数+第一个数之和,仍然保持除以B余b。即,第一个数+第二个数之和,为满足除以A余a,除以B余b。

依此类推,按上面的方法寻找到除以各素因子的余数的数之总和,为满足除以各素因子余数的条件的数。总和再减去能被这几个素数共同整除的数(A*B*C*D*…*Z)N后,其差仍然保持除以各素因子余数的条件的数。由此构成孙子定理的解法。
例题:
   x mod 3=2
   x mod 5=3
   x mod 7=2
m1=3 m2=5 m3=7  b1=2 b2=3 b3=2
m=m1*m2*m3=3*5*7
M1=m/m1=5*7  M1’=Mi(mi)-1mod mi=2
M2=m/m2=3*7  M2’=Mi(mi)-1mod mi=1
M3=m/m3=3*5  M3’=Mi(mi)-1mod mi=1
x=(M1’M1b1+M2’M2b2+…+M’kMkbk )mod m
=(2*5*7*2+1*3*7*3+1*3*5*2)mod 105
=(140+63+30) mod 105=233 mod 105=23

三、问题解决

      有了上面的普及,可以得到我们要的式子:Days=(5544*p+14421*i+1288*e)%21252.看到输入数据的0,应该是代表第一天的意思吧,有点难以理解。

import java.util.Scanner;
public class N1006_Biorhythms{
	
    public static void main(String args[]){
    	Scanner cin=new Scanner(System.in);
    	int num=0;
    	while(cin.hasNext()){
    		int p =cin.nextInt();
    		int e =cin.nextInt();
    		int i =cin.nextInt();
    		int d =cin.nextInt();
    		if(p==-1 && e==-1 && i==-1 && d==-1){
    			break;
    		}
    		num++;
    		int days=(5544 * p + 14421 * e + 1288 * i) % 21252 -d;
    		if(days <= 0){
    			days+=21252;
    		}
    		System.out.println("Case "+num+": the next triple peak occurs in "+days+" days.");
    	}
    }
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

原文地址:https://www.cnblogs.com/AndyDai/p/4734213.html