Bailian2793 孙子问题
Posted tigerisland45
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bailian2793 孙子问题相关的知识,希望对你有一定的参考价值。
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 10
long 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("
");
}
return 0;
}
以上是关于Bailian2793 孙子问题的主要内容,如果未能解决你的问题,请参考以下文章