CJOJ 1995 中国剩余定理(HDU1788)

该博客讨论了如何应用中国剩余定理解决一个数论问题:找到一个正整数N,使得N除以M1余(M1 - a),除以M2余(M2-a),以此类推。博客提供了问题描述、输入输出格式、样例以及解决方案,并提到了源问题来自数论领域的经典题目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

中国剩余定理(HDU1788)

Description

我知道部分同学最近在看中国剩余定理,就这个定理本身,还是比较简单的:
假设m1,m2,…,mk两两互素,则下面同余方程组:
x≡a1(mod m1)
x≡a2(mod m2)

x≡ak(mod mk)
在0<=记Mi=M/mi(1<=i<=k),因为(Mi,mi)=1,故有二个整数pi,qi满足Mipi+miqi=1,如果记ei=Mi/pi,那么会有:
ei≡0(mod mj), j!=i
ei≡1(mod mj), j=i
很显然,e1a1+e2a2+…+ekak就是方程组的一个解,这个解加减M的整数倍后就可以得到最小非负整数解。
这就是中国剩余定理及其求解过程。
现在有一个问题是这样的:
一个正整数N除以M1余(M1 - a),除以M2余(M2-a), 除以M3余(M3-a),总之, 除以MI余(MI-a),其中(a < Mi < 100 i=1,2,…I),求满足条件的最小的数。

Input

输入数据包含多组测试实例,每个实例的第一行是两个整数I(1 < I <10)和a,其中,I表示M的个数,a的含义如上所述;
紧接着的一行是I个整数M1,M2...MI,I=0 并且a=0结束输入,不处理。

Output

对于每个测试实例,请在一行内输出满足条件的最小的数。每个实例的输出占一行。
如果不存在这样的最小的数,输出-1.

Sample Input

2 1
2 3
0 0

Sample Output

5

Source

数论,欧几里得,中国剩余定理

Solution

中国剩余定理的板子题

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define L
#define LL long long
using namespace std;

inline int gi() {
  char cj = getchar();
  int ans = 0, f = 1;
  while (cj < '0' || cj > '9') {
    if (cj == '-') f = -1;cj = getchar();
  }
  while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar();
  return f * ans;
}

int I, a, r[10], m[10];

inline LL gcd(LL a, LL b) {
  return (a % b == 0) ? b : gcd(b, a % b);
}

inline void exgcd(LL a, LL b, LL& x, LL& y) {
  if (!b) x = 1, y = 0;
  else {
    exgcd(b, a % b, y, x);
    y -= (a / b) * x;
  }
}

inline LL solve() {
  LL M = m[1], R = r[1];
  for (int i = 2; i <= I; ++i) {
    LL d = gcd(M, m[i]), c = r[i] - R;
    if (c % d) return -1;
    LL x, y;
    exgcd(M / d, m[i] / d, x, y);
    x = (c / d * x) % (m[i] / d);
    R += x * M, M = M / d * m[i];
    R %= M;
  }
  if (R < 0) R += M;
  return R;
}

int main(){
  freopen("CJOJ1995.in", "r", stdin);
  freopen("CJOJ1995.out", "w", stdout);
  while (scanf("%d %d", &I, &a) != EOF && I && a) {
    memset(r, 0, sizeof(r));
    memset(m, 0, sizeof(m));
    for (int i = 1; i <= I; ++i) scanf("%d", &m[i]), r[i] = m[i] - a;
    printf("%lld\n", solve());
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值