中国剩余定理

中国剩余定理 算法 (CRT) 信息学竞赛


前置技能

扩展欧几里得算法:
求出形似

ax+by=1gcd(a,b)=1

也即
ax+by=gcd(a,b)

的一组解 x,y


问题模型

x 满足以下模方程

xmodxmodxmodxmodp1=a1p2=a2p2=a3pm=amp1,p2,,pm

求最小的

xmod(p1p2p3pm)


解决方案

1> 我们先解决 m=2 的情况

{xmodp1xmodp2=a1=a2

xmod(p1p2)
的值

我们设两个中间变量 r,s ,并将式子改变为

{x+rp1x+sp2=a1=a2

rp1sp2=a1a2

我们再设另外两个中间变量 r,s 满足

{rs=r(a1a2)=s(a1a2)

则上式变为

rp1+sp2=1

此时,我们可以就通过扩展欧几里得求得 r,s
回带即可得到一个 xmod(p1p2) 的值了

2> 多个式子的合并

我们注意到两个式子合并为了一个方程

xmod(p1p2)=b

这个方程的形式与其他方程的形式相同,并且模数互质,所以我们可以对这些方程两两合并


例题

韩信点兵

/****************************************\
* Author : ztx
* Title  : [cogs] 1786. 韩信点兵
* ALG    : CRT
* CMT    :
* Time   :
\****************************************/

#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
typedef double lf ;
typedef long double llf ;
typedef unsigned uint ;
typedef unsigned long long ull ;
#define  Getchar()  getchar()
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=Getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = Getchar() ;
    while (ret = ret*10+CH-'0' , CH=Getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
    while (ret=Getchar() , ret<'!') ;
    while (CH=Getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
    ret[0]=0;while (CH=Getchar() , CH<'!') ;
    while (ret[++ret[0]]=CH,CH=Getchar(),CH>'!') ;
    ret[ret[0]+1] = 0 ;
}

#define  maxm  11LL
#define  abss(x)  ((x)<0?-(x):(x))

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

inline ll mul(ll a,ll b,ll module) {
    ll ret = a*b-((ll)((llf)a*b/(llf)module+1E-3))*module ;
    return (ret+module)%module ;
}

ll p[maxm] , a[maxm] ;

int main() {
int i , m ;
ll n , x , y , module ;
    #define READ
    #ifdef  READ
        freopen("HanXin.in" ,"r",stdin ) ;
        freopen("HanXin.out","w",stdout) ;
    #endif
    read(n) , read(m) ;
    read(p[1]) , read(a[1]) ;
    module = p[1] ;
    Rep (i,2,m) {
        read(p[i]) , read(a[i]) ;
        exgcd(module,p[i],x,y) ;
        if (y < 0) y += module ;
        module *= p[i] ;
        y = mul(y,abss(a[i]-a[i-1]),module) ;
        a[i] = (a[i]-mul(abss(y),p[i],module)) % module ;
    }
    ll ans = n-a[m]-(n-a[m])/module*module ;
    if (ans > n) puts("-1") ;
    else printf("%lld\n", ans) ;
    #ifdef  READ
        fclose(stdin) ; fclose(stdout) ;
    #else
        Getchar() ; Getchar() ;
    #endif
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值