P3868&&P1495&&ybtoj【数学基础】3章4题【中国剩余定理【CRT】】

本文介绍了中国剩余定理(CRT)的基本概念和应用,详细解析了相关题目P3868和P1495,并提供了求解最小正整数n的方法。内容包括CRT的证明、逆元计算以及解题代码展示。
摘要由CSDN通过智能技术生成

中国剩余定理【CRT】

题目

P3868
P1495
ybtoj同P1495


解析

题意:给定 a 1 … k a_{1…k} a1k b 1 … k b_{1…k} b1k,求满足
{ ( n − a 1 ) ∣ b 1 ( n − a 2 ) ∣ b 2 . . . ( n − a k ) ∣ b k \left\{\begin{aligned}(n-a_1)\mid b_1 \\ (n-a_2)\mid b_2\\ ...\\ (n-a_k)\mid b_k\end{aligned}\right. (na1)b1(na2)b2...(nak)bk
的最小正整数n
显然的CRTChinese Re/Tle裸题,这里讲一下什么是CRT
中国剩余定理用于求解一个最小非负整数,使其满足
{ n ≡ a 1 ( m o d    m 1 ) n ≡ a 2 ( m o d    m 2 ) . . . n ≡ a k ( m o d    m k ) \left\{\begin{aligned} n\equiv a_1(\mod m_1)\\ n\equiv a_2(\mod m_2)\\...\\ n\equiv a_k(\mod m_k)\\ \end{aligned}\right. na1(modm1)na2(modm2)...nak(modmk)
其中m两两互质
M = ∏ i = 1 k m i M i = M m i T i = M i − 1 ( m o d    m i ) M=\prod_{i=1}^{k}m_i\qquad M_i=\frac{M}{m_i}\qquad T_i=M_i^{-1}(\mod m_i) M=i=1kmiMi=miMTi=Mi1(modmi)
M i T i ≡ 1 ( m o d    m i ) M_iT_i\equiv1(\mod m_i) MiTi1(modmi),有特解 a n s 0 = ∑ i = 1 k a i M i T i ans_0=\sum_{i=1}^{k}a_iM_iT_i ans0=i=1kaiMiTi,任意解 a n s = a n s 0 + k M ans=ans_0+kM ans=ans0+kM
注意到 m i m_i mi不一定为质数,我们需要用exgcd求逆元

证明:

∀ j ∈ [ 1 , k ] , i ≠ j ∀j∈[1,k],i≠j j[1,k],i=j,因 m i ∣ M j m_i\mid M_j miMj,故有 a j M j T j ≡ 0 ( m o d    m i ) a_jM_jT_j\equiv0(\mod m_i) ajMjTj0(modmi)
又因 M i T i ≡ 1 ( m o d    m i ) M_iT_i\equiv1(\mod m_i) MiTi1(modmi),故有 a i M i T i ≡ a i ( m o d    m i ) a_iM_iT_i\equiv a_i(\mod m_i) aiMiTiai(modmi)
故得证

逆元:

注意到 m i m_i mi不一定是质数,需要使用exgcd或欧拉定理求逆元

乘法:

P3868需要龟速乘

code(P3868):

#include<cstdio>
#define int long long
using namespace std;
inline void exgcd(int a,int b,int &x,int &y)
{
	if(b==0){x=1,y=0;return;}
	exgcd(b,a%b,x,y);
	int tmp=x;
	x=y,y=tmp-a/b*y;
}
int x,y;
inline int _(int a,int b)
{
	exgcd(a,b,x,y);
	return (y%a+a)%a;
}
int n,a[11],b[11],M=1,ans;
inline int mul(int xx,int yy)
{
	int res=0;
	while(yy){if(yy&1)res=((res+xx>=M)?(res+xx-M):(res+xx));yy>>=1,xx=((xx<<1)>=M)?((xx<<1)-M):(xx<<1);}
	return res;
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
	for(int i=1;i<=n;++i)scanf("%lld",&b[i]),M=M*b[i];
	for(int i=1;i<=n;++i)ans=(ans+mul(_(b[i],M/b[i]),mul(M/b[i],(a[i]+M)%M)))%M;
	printf("%lld",(ans<0)?(ans+M):ans);
	return 0;
}

code(P1495&&ybtoj):

#include<cstdio>
#define ll __int128
using namespace std;
inline bool idigit(char x){return (x<'0'|x>'9')?0:1;}
inline ll read()
{
	ll num=0,f=1;
	char c=0;
	while(!idigit(c=getchar())){if(c=='-')f=-1;}
	while(idigit(c))num=(num<<1)+(num<<3)+(c&15),c=getchar();
	return num*f;
}
inline void write(ll x)
{
	ll F[20];
	ll tmp=x>0?x:-x;
	if(x<0)putchar('-');
	ll cnt=0;
	while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}
	while(cnt>0)putchar(F[--cnt]);
	if(x==0)putchar('0');
}
inline void exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0){x=1,y=0;return;}
	exgcd(b,a%b,x,y);
	ll tmp=x;
	x=y,y=tmp-a/b*y;
}
ll x,y;
inline ll _(ll a,ll b)
{
	exgcd(a,b,x,y);
	return (x%b+b)%b;
}
ll n,a[11],b[11],M=1,ans;
int main()
{
	n=read();
	for(ll i=1;i<=n;++i)a[i]=read(),b[i]=read(),M*=a[i];
	for(ll i=1;i<=n;++i)ans+=b[i]*(M/a[i])*_(M/a[i],a[i]);
	write(ans%M);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值