Strange Way to Express Integers(扩展欧几里得+乘法逆元+中国剩余定理求解非互质的模线性方程组)

本文介绍了模线性方程组的求解方法,通过结合扩展欧几里得算法、乘法逆元和中国剩余定理,详细解释了如何找到最小满足给定模线性方程组的被除数。提供了两种实现方式:递归版和非递归版的AC代码。

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


Link:http://poj.org/problem?id=2891


Strange Way to Express Integers
Time Limit: 1000MS Memory Limit: 131072K
Total Submissions: 11454 Accepted: 3549

Description

Elina is reading a book written by Rujia Liu, which introduces a strange way to express non-negative integers. The way is described as following:

Choose k different positive integers a1a2…, ak. For some non-negative m, divide it by every ai (1 ≤ i ≤ k) to find the remainder ri. If a1a2, …, ak are properly chosen, m can be determined, then the pairs (airi) can be used to express m.

“It is easy to calculate the pairs from m, ” said Elina. “But how can I find m from the pairs?”

Since Elina is new to programming, this problem is too difficult for her. Can you help her?

Input

The input contains multiple test cases. Each test cases consists of some lines.

  • Line 1: Contains the integer k.
  • Lines 2 ~ k + 1: Each contains a pair of integers airi (1 ≤ i ≤ k).

Output

Output the non-negative integer m on a separate line for each test case. If there are multiple possible values, output the smallest one. If there are no possible values, output -1.

Sample Input

2
8 7
11 9

Sample Output

31

Hint

All integers in the input and the output are non-negative and can be represented by 64-bit integral types.

Source


题意:给出模线性方程组的每个式子的除数和余数,求最小满足这些式子的被除数是多少。若无解则输出-1。

编程思想:扩展欧几里得+乘法逆元+中国剩余定理。


AC code1(递归版):

/** 
中国剩余定理(不互质) 
*/  
#include <iostream>  
#include <cstdio>  
#include <cstring>  
using namespace std;  
typedef __int64 int64;  
int64 Mod;  
  
int64 gcd(int64 a, int64 b)  
{  
    if(b==0)  
        return a;  
    return gcd(b,a%b);  
}  
  
int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)//ax+by=gcd(a,b)  
{  
    if(b==0)  
    {  
        x=1,y=0;  
        return a;  
    }  
    int64 d = Extend_Euclid(b,a%b,x,y);  
    int64 t = x;  
    x = y;  
    y = t - a/b*y;  
    return d;  
}  
  
//a在模n乘法下的逆元,没有则返回-1  
int64 inv(int64 a, int64 n)  
{  
    int64 x,y;  
    int64 t = Extend_Euclid(a,n,x,y);  
    if(t != 1)  
        return -1;  
    return (x%n+n)%n;  
}  
  
//将两个方程合并为一个  
bool merge(int64 a1, int64 n1, int64 a2, int64 n2, int64& a3, int64& n3)  
{  
    int64 d = gcd(n1,n2);  
    int64 c = a2-a1;  
    if(c%d)  
        return false;  
    c = (c%n2+n2)%n2;  
    c /= d;  
    n1 /= d;  
    n2 /= d;  
    c *= inv(n1,n2);  
    c %= n2;  
    c *= n1*d;  
    c += a1;  
    n3 = n1*n2*d;  
    a3 = (c%n3+n3)%n3;  
    return true;  
}  
  
//求模线性方程组x=ai(mod ni),ni可以不互质  
int64 China_Reminder2(int len, int64* a, int64* n)//len为模方程的式子总数,a[i]、n[i]分别表示第i个式子的余数、除数  
{  
    int64 a1=a[0],n1=n[0];  
    int64 a2,n2;  
    for(int i = 1; i < len; i++)  
    {  
        int64 aa,nn;  
        a2 = a[i],n2=n[i];  
        if(!merge(a1,n1,a2,n2,aa,nn))  
            return -1;//无解输出-1  
        a1 = aa;  
        n1 = nn;  
    }  
    Mod = n1;  
    return (a1%n1+n1)%n1;  
}  
int64 a[1000],b[1000];  
int main()  
{  
    int i;  
    int k;  
    while(scanf("%d",&k)!=EOF)  
    {  
        for(i = 0; i < k; i++)  
            scanf("%I64d %I64d",&a[i],&b[i]);  
        printf("%I64d\n",China_Reminder2(k,b,a));  
    }  
    return 0;  
}


AC code2(非递归版):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#define PI acos(-1.0)
#define LINF 1000000000000000000LL
#define eps 1e-8
#define LL long long
#define MAXN 100010 
#define MOD 1000000007
using namespace std;
const int INF=0x3f3f3f3f;
LL Mod;  
LL gcd(LL a, LL b)  
{  
    if(b==0)  
        return a;  
    return gcd(b,a%b);  
}  
LL exgcd(LL A,LL &x,LL B,LL &y)
{
    LL x1,y1,x0,y0;
    x0=1;y0=0;
    x1=0;y1=1;
    LL r=(A%B+B)%B;
    LL q=(A-r)/B;
    x=0;y=1;
    while(r)
    {
        x=x0-q*x1;
        y=y0-q*y1;
        x0=x1;
        y0=y1;
        x1=x;y1=y;
        A=B;B=r;r=A%B;
        q=(A-r)/B;
    }
    return B;
}
LL ABS(LL x)
{
	return x>=0?x:-x;
}
/*接下来介绍乘法逆元:
若m≥1,gcd(a,m)=1,则存在c使得 ca≡1(mod m) 我们把c称为是a对模m的逆,记为 a-1(mod m)或a-1 可以用扩展欧几里德算法求a-1
应用: 求(a/b)%c时,若a为大整数时可以写成 ((a%c)*((b-1)%c))%c,注意:这里(b-1)是b%c的乘法逆元,不是b减 1!!! 
还可以使用扩展欧几里德算法求乘法逆元:*/
//a在模n乘法下的逆元,没有则返回-1(a * b % n == 1,已知a,n,求b就是求a模n的乘法逆元)    
LL inv(LL a, LL n)  
{  
    LL x,y;  
    //int64 t = Extend_Euclid(a,n,x,y); 
	/*******************************************
	扩展欧几里得算法求乘法逆元
	调用:exgcd(a,x,b,y);
	则:  x为a模b的乘法逆元,y为b模a的乘法逆元
	********************************************/ 
    LL t = exgcd(a,x,n,y);  
    if(t != 1)  
        return -1;  
    return (x%n+n)%n;  
}  
  
//将两个方程合并为一个  
bool merge(LL a1, LL n1, LL a2, LL n2, LL& a3, LL& n3)  
{  
    LL d = gcd(n1,n2);  
    LL c = a2-a1;  
    if(c%d)  
        return false;  
    c = (c%n2+n2)%n2;  
    c /= d;  
    n1 /= d;  
    n2 /= d;  
    c *= inv(n1,n2);  
    c %= n2;  
    c *= n1*d;  
    c += a1;  
    n3 = n1*n2*d;  
    a3 = (c%n3+n3)%n3;  
    return true;  
}  
  
//求模线性方程组x=ai(mod ni),ni可以不互质  
LL China_Reminder2(LL len, LL* a, LL* n)//len为模方程的式子总数,a[i]、n[i]分别表示第i个式子的余数、除数  
{  
    LL a1=a[0],n1=n[0];  
    LL a2,n2;  
    for(int i = 1; i < len; i++)  
    {  
        LL aa,nn;  
        a2 = a[i],n2=n[i];  
        if(!merge(a1,n1,a2,n2,aa,nn))  
            return -1;//无解输出-1  
        a1 = aa;  
        n1 = nn;  
    }  
    Mod = n1;  
    return (a1%n1+n1)%n1;  
}  
LL a[1000],b[1000];  
int main()  
{  
    int i;  
    int k;  
    while(scanf("%d",&k)!=EOF)  
    {  
        for(i = 0; i < k; i++)  
            scanf("%I64d %I64d",&a[i],&b[i]);  
        printf("%I64d\n",China_Reminder2(k,b,a));  
    }  
    return 0;  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林下的码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值