(数论)51NOD 1079 中国剩余定理

一个正整数K,给出K Mod 一些质数的结果,求符合条件的最小的K。例如,K % 2 = 1, K % 3 = 2, K % 5 = 3。符合条件的最小的K = 23。
 
Input
第1行:1个数N表示后面输入的质数及模的数量。(2 <= N <= 10)
第2 - N + 1行,每行2个数P和M,中间用空格分隔,P是质数,M是K % P的结果。(2 <= P <= 100, 0 <= K < P)
Output
输出符合条件的最小的K。数据中所有K均小于10^9。
Input示例
3
2 1
3 2
5 3
Output示例
23

解:
方法一
 1 #include <stdio.h>
 2 
 3 typedef struct
 4 {
 5     int p, m;
 6 }str;
 7 
 8 str s[10];
 9 
10 int cmp(const void *a, const void *b)
11 {
12     return ((str *)a)->p > ((str *)b)->p ? -1 : 1;
13 }
14 
15 int main()
16 {
17     int n;
18     while (scanf_s("%d", &n) != EOF)
19     {
20         long long mult = 1;
21         int ans;
22         for (int i = 0; i < n; i++)
23         {
24             scanf_s("%d%d", &s[i].p, &s[i].m);
25             mult *= s[i].p;
26         }
27         qsort(s, n, sizeof(str), cmp);
28         for (int i = 0, flag = 1; flag && i * s[0].p <= mult; i++)
29         {
30             ans = s[0].p * i + s[0].m;
31             for (int j = 1; ans % s[j].p == s[j].m;j++)
32             {
33                 if (j == n - 1)
34                 {
35                     flag = 0;
36                     break;
37                 }
38             }
39         }
40         printf("%d\n", ans);
41 
42     }
43 }

改进法一后的法二:

 1 #include <stdio.h>
 2 
 3 
 4 int main()
 5 {
 6     int n;
 7     while (scanf_s("%d", &n) != EOF)
 8     {
 9         int a, b, c, d;
10         scanf_s("%d%d", &a, &b);
11         for (int i = 1,j; i < n; i++)
12         {
13             scanf_s("%d%d", &c, &d);
14             for (j = 0; (a * j + b) % c != d; j++);
15             b = a * j + b;
16             a *= c;
17         }
18         printf("%d\n", b);
19     }
20 }

法三:

中国剩余定理(https://baike.baidu.com/item/孙子定理/2841597?fromtitle=%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86&fromid=11200132&fr=aladdin)+ 拓展欧几里得

(注意中国剩余定理必满足使用拓展欧几里得求逆元的条件,即n个不同质数,其中n-1个的乘积必与剩下的1个互质)

 1 #include <stdio.h>
 2 
 3 int inv[10], pm[20];
 4 
 5 void Ex_gcd(int a, int b, int *x, int *y);
 6 
 7 int main()
 8 {
 9     int t;
10     while (scanf_s("%d", &t) != EOF)
11     {
12         long long M = 1, ans = 0;
13         for (int i = 0; i < t; i++)
14         {
15             scanf_s("%d%d", &pm[i], &pm[i + 10]);
16             M *= pm[i];
17         }
18         for (int i = 0, temp; i < t; i++)
19         {
20             Ex_gcd(M / pm[i], pm[i], &inv[i], &temp);
21             inv[i] = (inv[i] + pm[i]) % pm[i];
22             ans = (ans + M / pm[i] * inv[i] * pm[i + 10]) % M;
23         }
24         printf("%d\n", ans);
25     }
26 }
27 
28 void Ex_gcd(int a, int b, int *x, int *y)
29 {
30     if (b == 0)
31     {
32         *x = 1;
33         *y = 0;
34         return;
35     }
36     Ex_gcd(b, a%b, x, y);       //或者可以这么写
37     int t = *y;                 //ex_gcd(b, a%b, y, x); 
38 *y = *x - a / b * (*y); //*y = *y - (a / b)**x; 39 *x = t; //return; 40 return; 41 }

 

 

转载于:https://www.cnblogs.com/Ekalos-blog/p/9671919.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值