2793:孙子问题
总时间限制: 15000ms 内存限制: 65536kB
描述
我国古代《孙子算经》中,记有如下算题:“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”并给出得数:“答曰:23。”
为解决这个问题民间流传了如下歌诀:“三人同行七十稀,五树梅花廿一枝,七子团员正半月,除百零五便得知。”
把上面的问题说得明白一点就是:有一个正整数N,除以3的余数是2,除以5的余数是3,除以7的余数是2,要求这个数。
民间给出的解法是:把N除以3的余数乘以70,把N除以5的余数乘以21,把N除以7的余数乘以15,把这三个结果加起来,最后把得到的结果除以105得到的就是答案。
其实在民间的解法中不除以105得到的也是一个符合题意的答案,而且民间的解法对于已知“除以3的余数,除以5的余数和除以7的余数” 的问题都能得到一个符合要求的答案。比如对于上面的问题,得到的结果是2 * 70 + 3 * 21 + 2 * 15 = 233,这个结果也能满足除以3的余数是2,除以5的余数是3,除以7的余数是2。如果已知的问题是“除以3的余数是1,除以5的余数是4,除以7的余数是4”,民间解法得到的结果1 * 70 + 4 * 21 + 4 * 15 = 214,这个结果也满足除以3的余数是1,除以5的余数是4,除以7的余数是4。
把这个问题推广到更普遍的情况:对于给定的正整数a1, a2, … an,是否存在正整数b1, b2, … bn,使得对于任意的一个正整数N,如果用N除以a1的余数是p1,用N除以a2的余数是p2……用N除以an的余数是pn,那么M = p1 * b1 + p2 * b2 + … + pn * bn能满足M除以a1的余数也是p1,M除以a2的余数也是p2……M除以an的余数也是pn。
输入
输入包括多组测试数据,每组数据包括一行。在每组数据中,首先给出ai的个数n (1 <= n <= 10),然后给出n个不大于50的正整数a1, a2, … an。最后一组测试数据中n = 0,表示输入的结束,这组数据不用处理。
输出
对于每一组测试数据,输出一行,如果存在正整数b1, b2, … bn满足题意,则输出这n个正整数(数的长度不要超过50位)如果有多组答案,输出任意一组即可,相邻的正整数之间用一个空格隔开;否则,输出“NO”。
样例输入
3 3 5 7
0
样例输出
70 21 15
提示
这题使用了special judge,使用special judge一般不判断Presentation Error,因此请大家注意输出格式。
问题链接: Bailian2793 孙子问题
问题描述:(略)
问题分析:
使用扩展欧几里德算法实现中国剩余定理。
程序说明:
变量类型为int会WA,需要是long类型。
参考链接:(略)
题记:(略)。
AC的C语言程序如下:
/* Bailian2793 孙子问题 */#include <stdio.h>#define N 10long a[N], p[N], q[N + 1], gc[N], gd[N], k[N], res[N];// 递归法实现扩展欧几里德算法long exgcd(long a, long b, long *x, long *y){long d;if(b == 0) {*x = 1;*y = 0;return a;}d = exgcd(b, a % b, x, y);long t = *x;*x = *y;*y = t - a / b * *y;return d;}int main(void){long lcm, rem, gcd, x, y, g, r;int n, i;while(scanf("%d", &n) != EOF && n) {for(i = 0; i < n; i++)scanf("%ld", &a[i]);lcm = a[0];for(i = 0; i < n; i++)lcm = lcm / exgcd(lcm, a[i], &x, &y) * a[i];for(i = 0; i < n; i++)p[i] = q[i] = lcm / a[i];q[n] = lcm;g = p[n - 1];gc[n - 1] = lcm;for(i = n - 1; i > 0; i--) {gc[i - 1] = exgcd(g, p[i], &x, &y);g = gc[i - 1];}for(i = 0; i < n; i++)gd[i] = gc[i];rem = 1;for(i = 0; i < n; i++) {gcd = exgcd(p[i], gc[i], &x, &y);q[i] /= gcd;gd[i] /= gcd;r = rem;while(r < 0)r += lcm;r /= gcd;r %= gd[i];exgcd(q[i], gd[i], &x, &y);k[i] = r * x;while(k[i]<=0)k[i] += a[i];res[i] = p[i];res[i] *= k[i];rem -= res[i];}for(i =0 ; i < n; i++)printf("%ld ", res[i]);printf("\n");}return 0;}