其他分享
首页 > 其他分享> > 【poj1006】 Biorhythms

【poj1006】 Biorhythms

作者:互联网

点击题目链接

Biorhythms
Time Limit: 1000MS Memory Limit: 10000K

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天。一个周期内有一天为峰值,在这一天,人在对应的方面(体力,情感或智力)表现最好。通常这三个周期的峰值不会是同一天。现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现。

解题思路1

  参考中国剩余定理SCL、拓展中国剩余定理SCL

  我们易得:m1=23m2=28m3=33m_1=23,m_2=28,m_3=33m1​=23,m2​=28,m3​=33,a1=pa2=ea3=ia_1=p,a_2=e,a_3=ia1​=p,a2​=e,a3​=i,且m1,m2,m3m_1,m_2,m_3m1​,m2​,m3​三个数互质。
  那么我们就直接用模版接口套公式做就可以。

  但这里要注意两点:

  1. 因为SCL中int CRT(int a[],int m[],int n);最后返回的是(ret+M)%M。其中M为m1,m2,m3m_1,m_2,m_3m1​,m2​,m3​的乘积,所以当 a1=0,a2=0,a3=0a_1=0,a_2=0,a_3=0a1​=0,a2​=0,a3​=0 的时候。得到的是(0+M)%M=0,得到的答案再减去输入的d,明显不符合要求。这时应该得到的正好是M才合理。

  2. 如果只解决上面那一种特殊情况,提交代码还是会WA。因为通过上面那种特殊情况我们可以反思其他的特殊情况:
    //提供一组特殊数据
    //23 28 33 0 21252
    //23 28 33 1 21251
    //23 28 33 2 21250
    //24 29 34 0 1
    //24 29 34 1 21252
    //24 29 34 2 21251
    //46 56 66 0 21252
    //46 56 66 1 21251
    //46 56 66 2 21250

  原来我们可以发现,(ret+M)%M代表的其实是一个循环数,在0~M-1循环,如果到M,则自动变为0。所以如果(ret+M)%M-d<=0(不在答案范围),可以用循环数把它变为在范围内的数。

  参考下面代码操作:
注:如果对两个函数接口不熟悉的可以参考中国剩余定理SCL、拓展中国剩余定理SCL这篇博客。

#include <iostream>
using namespace std;

int extend_gcd( int a, int b, int &x, int &y )//拓展欧几里得
{
	if( b==0 )
	{
		x = 1;
		y = 0;
		return a;
	}
	else
	{
		int r = extend_gcd(b,a%b,y,x);
		y -= x*(a/b);
		return r;
	}
}

int CRT( int a[], int m[], int n )//中国剩余定理
{
	int M = 1;
	for(int i=0;i<n;++i) M *= m[i];
	int ret = 0;
	for(int i=0;i<n;++i)
	{
		int x,y;
		int tm = M/m[i];
		extend_gcd(tm,m[i],x,y);//调用外部函数:拓展欧几里得
		ret = (ret+tm*x*a[i])%M;
	}
	return (ret+M)%M;
}

int main()
{
    ios::sync_with_stdio(0);
    int a[3],m[3]={23,28,33};
    int d,ans,case_i=1;
    while( cin>>a[0]>>a[1]>>a[2]>>d && a[0]!=-1 )
    {
        ans = CRT(a,m,3)-d;
        if( ans<=0 ) ans = 23*28*33+ans;
        cout << "Case " << case_i++ << ": the next triple peak occurs in " << ans << " days." << endl;
    }
}

解题思路2

  上面那个思路是让计算机帮我们做算术,那如果我们想自己动手算直接得答案呢?

  还是参考中国剩余定理SCL、拓展中国剩余定理SCL这篇中分析的结果:

  中国剩余定理的公式:
  设正整数m1,m2,...,mkm_1,m_2,...,m_km1​,m2​,...,mk​两两互素,则同余方程组
          {xa1(mod m1)xa2(mod m2)xa3(mod m3)    .    .    .xak(mod mk)\begin{cases} x\equiv a_1(mod\space m_1)\\ x\equiv a_2(mod\space m_2)\\ x\equiv a_3(mod\space m_3)\\ \space\space\space\space .\\ \space\space\space\space .\\ \space\space\space\space .\\ x\equiv a_k(mod\space m_k)\end{cases}⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧​x≡a1​(mod m1​)x≡a2​(mod m2​)x≡a3​(mod m3​)    .    .    .x≡ak​(mod mk​)​

  有整数解。并且在模 M=m1m2...mkM=m_1\cdot m_2\cdot...\cdot m_kM=m1​⋅m2​⋅...⋅mk​下的解是唯一的,解为
    x(a1M1M11+a2M2M21+...+akMkMk1)mod Mx\equiv(a_1M_1M_1^{-1}+a_2M_2M_2^{-1}+...+a_kM_kM_k^{-1})mod\space Mx≡(a1​M1​M1−1​+a2​M2​M2−1​+...+ak​Mk​Mk−1​)mod M
  其中 Mi=M/miM_i=M/m_iMi​=M/mi​ ,而 Mi1M_i^{-1}Mi−1​ 为 MiM_iMi​ 模 mim_imi​ 的逆元。

  其中,据题意易得a1=pa2=ea3=i,且M=23*28*33=21252M1=M/m1=28*33=924M2=23*33=759M3=23*28=644,且m1=23m2=28m3=33

  那么困难就在于手算逆元Mi1M_i^{-1}Mi−1​,为了方便表示,我们把Mi1M_i^{-1}Mi−1​记为 yiy_iyi​,我们根据逆元的定义:Miyi1(mod mi)M_i*y_i\equiv 1(mod\space m_i)Mi​∗yi​≡1(mod mi​)求解各个 yiy_iyi​ 即可。

  易得三个联立方程:

          {M1y11 (mod m1)M2y21 (mod m2)M3y31 (mod m3)\begin{cases} M_1y_1\equiv 1\space(mod\space m_1)\\ M_2y_2\equiv 1\space(mod\space m_2)\\ M_3y_3\equiv 1\space(mod\space m_3)\\ \end{cases}⎩⎪⎨⎪⎧​M1​y1​≡1 (mod m1​)M2​y2​≡1 (mod m2​)M3​y3​≡1 (mod m3​)​

  我们拿第一个方程来演示同余方程的解法:

          M1y11 (mod m1)M_1y_1\equiv 1\space(mod\space m_1)M1​y1​≡1 (mod m1​)
\Rightarrow⇒          924y11 (mod 23)\space\space924y_1\equiv 1\space(mod\space 23)  924y1​≡1 (mod 23)
\Rightarrow⇒    (4023+4)y11 (mod 23)(40*23+4)y_1\equiv 1\space(mod\space 23)(40∗23+4)y1​≡1 (mod 23)
\Rightarrow⇒          4y11 (mod 23)4y_1\equiv 1\space(mod\space 23)4y1​≡1 (mod 23)(利用同余式数乘原理,两边同乘6)
\Rightarrow⇒          24y16 (mod 23)24y_1\equiv 6\space(mod\space 23)24y1​≡6 (mod 23)
\Rightarrow⇒          (231+1)y16 (mod 23)(23*1+1)y_1\equiv 6\space(mod\space 23)(23∗1+1)y1​≡6 (mod 23)
\Rightarrow⇒          y16 (mod 23)y_1\equiv 6\space(mod\space 23)y1​≡6 (mod 23)

  即得到M11=y1=6M_1^{-1}=y_1=6M1−1​=y1​=6

  同理,第二个方程的解法:

          M2y21 (mod m2)M_2y_2\equiv 1\space(mod\space m_2)M2​y2​≡1 (mod m2​)
\Rightarrow⇒          759y21 (mod 28)\space\space759y_2\equiv 1\space(mod\space 28)  759y2​≡1 (mod 28)
\Rightarrow⇒    (2728+3)y21 (mod 28)(27*28+3)y_2\equiv 1\space(mod\space 28)(27∗28+3)y2​≡1 (mod 28)
\Rightarrow⇒          3y21 (mod 28)3y_2\equiv 1\space(mod\space 28)3y2​≡1 (mod 28)(利用同余式数乘原理,两边同乘9)
\Rightarrow⇒          27y29 (mod 28)27y_2\equiv 9\space(mod\space 28)27y2​≡9 (mod 28)
\Rightarrow⇒     (2811)y29 (mod 28)(28*1-1)y_2\equiv 9\space(mod\space 28)(28∗1−1)y2​≡9 (mod 28)
\Rightarrow⇒          y29 (mod 28)-y_2\equiv 9\space(mod\space 28)−y2​≡9 (mod 28)
\Rightarrow⇒           y29 (mod 28)y_2\equiv -9\space(mod\space 28)y2​≡−9 (mod 28)
\Rightarrow⇒           y2(2819) (mod 28)y_2\equiv (28*1-9)\space(mod\space 28)y2​≡(28∗1−9) (mod 28)
\Rightarrow⇒           y219 (mod 28)y_2\equiv 19\space(mod\space 28)y2​≡19 (mod 28)

  即得到M21=y2=19M_2^{-1}=y_2=19M2−1​=y2​=19

  同理,解得M31=y3=2M_3^{-1}=y_3=2M3−1​=y3​=2

  x(a1M1M11+a2M2M21+a3M3M31)mod Mx\equiv(a_1M_1M_1^{-1}+a_2M_2M_2^{-1}+a_3M_3M_3^{-1})mod\space Mx≡(a1​M1​M1−1​+a2​M2​M2−1​+a3​M3​M3−1​)mod M,那么代入各个已知的值便可以得到本题的求解公式:

  x(9246p+75919a2+6442a3)mod 21252x\equiv(924*6*p+759*19*a_2+644*2*a_3)mod\space 21252x≡(924∗6∗p+759∗19∗a2​+644∗2∗a3​)mod 21252
x(5544p+14421a2+1288a3)mod 21252x\equiv(5544*p+14421*a_2+1288*a_3)mod\space 21252x≡(5544∗p+14421∗a2​+1288∗a3​)mod 21252

  参考下面代码操作:

#include <iostream>
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    int p,e,i,d,ans,case_i=1;
    while( cin>>p>>e>>i>>d && p!=-1 )
    {
        ans = (5544*p+14421*e+1288*i)%21252-d;
        if( ans<=0 ) ans = 23*28*33+ans;
        cout << "Case " << case_i++ << ": the next triple peak occurs in " << ans << " days." << endl;
    }
}

标签:23,int,Biorhythms,28,space,poj1006,equiv,mod
来源: https://blog.csdn.net/Sherry_Yue/article/details/88614512