poj 1006、2891(中国剩余定理 及扩展 模板)

中国剩余定理来源及推导:https://www.cnblogs.com/MashiroSky/p/5918158.html
中国剩余定理(CRT)表述及模板:https://blog.csdn.net/acdreamers/article/details/8050018


中国剩余定理——求解一次同余式组 x ≡ a i ( m o d   m i ) x\equiv a_i(mod\ m_i) xai(mod mi)的方法:
注:要求所有的模数 m i m_i mi互质

int CRT(int* a,int* m,int n)//余数、模数、同余式组个数
{
    int ans=0,M=1;//M为所有模数的乘积
    for(int i=1;i<=3;i++)M*=m[i];
    for(int i=1;i<=n;i++)
    {
        int x,y;
        int Mi=M/m[i];
        //Mi*x=1(mod m[i])
        //Mi*x+m[i]*y=1
        exgcd(Mi,m[i],x,y);//求Mi关于m[i]的逆元x
        (ans+=a[i]*Mi*x)%=M;
    }
    if(ans<0)ans+=M;
    return ans;
}

题目:http://poj.org/problem?id=1006

#include
#include
#include
#include
using namespace std;
const int manx=2e3;

int m[manx],a[manx];
int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int gcd=exgcd(b,a%b,x,y);
    int temp=x;
    x=y;
    y=temp-(a/b)*y;
    return gcd;
}
int CRT(int* a,int* m,int n)
{
    int ans=0,M=1;
    for(int i=1;i<=3;i++)M*=m[i];
    for(int i=1;i<=n;i++)
    {
        int x,y;
        int Mi=M/m[i];
        exgcd(Mi,m[i],x,y);
        (ans+=a[i]*Mi*x)%=M;
    }
    if(ans<0)ans+=M;
    return ans;
}
int main()
{
    int p,e,i,d,cou=1,M;
    while(scanf("%d%d%d%d",&p,&e,&i,&d)!=EOF)
    {
        if(p==-1&&e==-1&&i==-1&&d==-1)
            break;
        a[1]=p%23;
        a[2]=e%28;
        a[3]=i%33;
        m[1]=23;
        m[2]=28;
        m[3]=33;
        int ans=CRT(a,m,3,M);
        if(d>=ans)
            ans+=21252;
        printf("Case %d: the next triple peak occurs in %d days.\n",cou++,ans-d);
    }
    return 0;
}

中国剩余定理扩展——求解模数不互质情况下的线性方程组:
x ≡ a i ( m o d   m i ) x\equiv a_i(mod\ m_i) xai(mod mi)
转化一下:
x = a 1 + m 1 x 1 x=a_1+m_1x_1 x=a1+m1x1
x = a 2 + m 2 x 2 x=a_2+m_2x_2 x=a2+m2x2( x = a 2 − m 2 x 2 x=a_2-m_2x_2 x=a2m2x2)
两两合并。左边相等,通过扩欧求出 x 1 x_1 x1(或 x 2 x_2 x2)的最小整数解,然后带回得到 x x x的最小整数解 x ′ x' x,即得 x x x的通解 x = x ′ + k ∗ l c m ( m 1 , m 2 ) x=x'+k*lcm(m_1,m_2) x=x+klcm(m1,m2)
x ≡ x ′ ( m o d   l c m ( m 1 , m 2 ) ) x\equiv x'(mod\ lcm(m_1,m_2)) xx(mod lcm(m1,m2))

#include
typedef long long LL;
const int manx=2e3;

LL m[manx],a[manx];
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    LL gcd=exgcd(b,a%b,x,y);
    LL temp=x;
    x=y;
    y=temp-(a/b)*y;
    //LL gcd=exgcd(b,a%b,y,x);
    //y-=(a/b)*x;
    return gcd;
}
LL ex_CRT(LL* a,LL* m,LL n)//余数、模数、同余式组个数
{
    for(int i=2; i<=n; i++)
    {
        LL x,y,c=a[i]-a[i-1];
        //x=a1+m1x1=a2-m2x2
        //m1x1+m2x2=a2-a1=c
        LL gcd=exgcd(m[i-1],m[i],x,y);
        if(c%gcd)
            return -1;
        x=x*c/gcd;
        LL temp=m[i]/gcd;
        x=(x%temp+temp)%temp;//求x1的最小正整数解
        a[i]=a[i-1]+x*m[i-1],m[i]=m[i]*m[i-1]/gcd;
    }
    return a[n];
}
int main()
{
    LL k,a[manx],r[manx];
    while(~scanf("%I64d",&k))
    {
        for(int i=1; i<=k; i++)
            scanf("%I64d%I64d",&a[i],&r[i]);
        LL ans=ex_CRT(r,a,k);
        printf("%I64d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(其他数学内容,欧拉函数,欧几里得算法)