中国剩余定理

来源:互联网 发布:从来绝色知难得打一字 编辑:程序博客网 时间:2024/06/15 14:27

中国剩余定理 算法 (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
原创粉丝点击