题目

源地址:

http://poj.org/problem?id=1006

理解

基本上就是孙子兵法,求那个最小的公倍数。记得华罗庚先生也写过同余式的相关著作。恩,找出规律之后,轻松水掉。

新技能get

中国剩余定理(离开校网之后再也连不上wiki了,只好引用百度百科的资料)

在中国古代劳动人民中,长期流传着“隔墙算”、“剪管术”、“秦王暗点兵”等数学游戏。有一首“孙子歌”,甚至远渡重洋,输入日本: “三人同行七十稀,五树梅花廿一枝,七子团圆正半月,除百零五便得知。” 这些饶有趣味的数学游戏,以各种不同形式,介绍世界闻名的“孙子问题”的解法,通俗地反映了中国古代数学一项卓越的成就。“孙子问题”在现代数论中是一个一次同余问题,它最早出现在中国公元四世纪的数学著作《孙子算经》中。《孙子算经》卷下“物不知数”题说:有物不知其数,三个一数余二,五个一数余三,七个一数又余二,问该物总数几何?显然,这相当于求不定方程组N=3x+2,N=5y+3,N=7z+2的正整数解N,或用现代数论符号表示,等价干解下列的一次同余组。 《孙子算经》所给答案是N=23。由于孙子问题数据比较简单,这个答数通过试算也可以得到。但是《孙子算经》并不是这样做的。“物不知数”题的术文指出解题的方法多三三数之,取数七十,与余数二相乘;五五数之,取数二十一,与余数三相乘;七七数之,取数十五,与余数二相乘。将诸乘积相加,然后减去一百零五的倍数。列成算式就是: N=70×2+21×3+15×2-2×105。 这里105是模数3、5、7的最小公倍数,容易看出,《孙子算经》给出的是符合条件的最小正整数。对于一般余数的情形,《孙子算经》术文指出,只要把上述算法中的余数2、3、2分别换成新的余数就行了。以R1、R2、R3表示这些余数,那么《孙子算经》相当于给出公式 N=70×R1+21×R2+15×R3-P×105(p是整数)。 孙子算法的关键,在于70、21和15这三个数的确定。后来流传的《孙子歌》中所说“七十稀”、“廿一枝”和“正半月”,就是暗指这三个关键的数字。《孙子算经》没有说明这三个数的来历。实际上,它们具有如下特性: 也就是说,这三个数可以从最小公倍数M=3×5×7=105中各约去模数3、5、7后,再分别乘以整数2、1、1而得到。假令k1=2,K2=1,K3=1,那么整数Ki(i=1,2,3)的选取使所得到的三数70、21、15被相应模数相除的时候余数都是1。由此出发,立即可以推出,在余数是R1、R2、R3的情况下的情况。 应用上述推理,可以完全类似地把孙子算法推广到一般情形:设有一数N,分别被两两互素的几个数a1、a2、……an相除得余数R1、R2、……Rn,即 N≡Ri(mod ai)(i=1、2、……n), 只需求出一组数K,使满足 1(mod ai)(i=1、2、……n), 那么适合已给一次同余组的最小正数解是 (P是整数,M=a1×a2×……×an), 这就是现代数论中著名的剩余定理。如上所说,它的基本形式已经包含在《孙子算经》“物不知数”题的解法之中。不过《孙子算经》没有明确地表述这个一般的定理。

代码

#include <stdio.h>

using namespace std;

#define P 23
#define E 28
#define I 33
#define C 21252

int main(void)
{
    int p, e, i, d;
    int x;

    int flag = 1;
    while (scanf("%d %d %d %d", &p, &e, &i, &d)&&p>=0)
    {
        p %= P;
        e %= E;
        i %= I;
        x = i;

        while (!((x - p) % P == 0 && (x - e) % E == 0))
        {
            x += I;
        }

        x -= d;
        if (x <= 0) x += C;
        printf("Case %d: the next triple peak occurs in %d days.\n", flag, x);
        flag++;
    }

    return 0;
}

更新日志

  • 2014年07月06日 已AC,完成中国剩余定理资料引用。