中国剩余定理/扩展中剩余定理

中国剩余定理

在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。具体解法分三步:

  • 找出三个数:从3和5的公倍数中找出被7除余1的最小数15,从3和7的公倍数中找出被5除余1 的最小数21,最后从5和7的公倍数中找出除3余1的最小数70。
  • 用15乘以2(2为最终结果除以7的余数),用21乘以3(3为最终结果除以5的余数),同理,用70乘以2(2为最终结果除以3的余数),然后把三个乘积相加15∗2+21∗3+70∗2得到和233。
  • 用233除以3,5,7三个数的最小公倍数105,得到余数23,即233%105=23。这个余数23就是符合条件的最小数。

类比古人 我们假设n1除以3余2,n2除以5余3,n3除以7余2;
且n1+n2+n3满足

  1. 使n1+n2+n3的和满足除以3余2,n2和n3必须是3的倍数。
  2. 使n1+n2+n3的和满足除以5余3,n1和n3必须是5的倍数。
  3. 使n1+n2+n3的和满足除以7余2,n1和n2必须是7的倍数。
    因此,为使n1+n2+n3的和作为“孙子问题”的一个最终解,需满足
    1.n1 除以3余2,且是5和7的公倍数。
    2.n2除以5余3,且是3和7的公倍数。
    3.n3 除以7余2,且是3和5的公倍数。
    再使用逆元 即可求解
    在这里插入图片描述
    有整数解(mi两两互质)在这里插入图片描述
    在这里插入图片描述
    Mi为M/mi; M i − 1 Mi^{-1} Mi1为Mi的逆元

crt 板子

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
ll a[150],b[150],n,m=1,ans=0;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    ll d;
    if(b==0)
    {
        x=1;y=0;return a;
    }
    else
    {
        d=exgcd(b,a%b,x,y);
        ll t=x;x=y;y=t-a/b*y;
        return d; 
    }
}
ll x,y,mi,d;
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld%lld",&a[i],&b[i]);m*=a[i];
    }
    for(ll i=1;i<=n;i++)
    {
        mi=m/a[i];
        d=exgcd(mi,a[i],x,y);
        ans=((ans+mi*x*b[i])%m+m)%m;
    }
    printf("%lld\n",ans);
    return 0;
}

excrt

在这里插入图片描述在这里插入图片描述

excrt Code 板子


#include<bits/stdc++.h>
#define ll __int128
using namespace std;
ll x,y,d,n; 
void exgcd(ll a,ll b,ll &x,ll &y){
	if(!b) d=a,x=1,y=0;
	else exgcd(b,a%b,y,x),y-=a/b*x;
}
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
ll a,b,A,B;
void merge(){
	exgcd(a,A,x,y);
	ll c=B-b;
	if(c%d) puts("-1"),exit(0);
	x=(x*c/d+A/d)%(A/d);
	ll mod=lcm(a,A);
	b=(a*x+b+mod)%mod;
	a=mod;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		long long u,v;
		scanf("%lld%lld",&u,&v);
		A=u,B=v;
		if(i>1) merge();
		else a=A,b=B;
	}
	printf("%lld\n",(long long)(b%a));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值