学习拓展中国剩余定理小结

前言

话说中国剩余定理好早就会了,但是一直木有接触过拓展的。
只知道它是个什么东东。
最近似乎需要它了,稍微学了学,似乎还挺简单的。
小结一下~

简介

中国剩余定理我们都懂吧?
而拓展则是把它后面的模数变成一个非质数,(当然,各个方程的模数互质)。
然后求出最小的x的解。

做法

似乎拓展之后很难用原来的套路来搞了。
怎么办?
我们发现,我们可以利用一些奇怪的推柿子大法来合并柿子。

考虑合并一下两个柿子:
\(x \equiv c1 (mod\ m1)\)
\(x \equiv c2 (mod\ m2)\)
转化一下:
\(x=c1+m1*k1\)
\(x=c2+m2*k2\)
合并、移项
\(m1*k1=c2-c1+m2*k2\)
设\(g=gcd(m1,m2)\)
柿子两边同除g得:
\(\frac{m1}g*k1=\frac{c2-c1}g+\frac{m2}g*k2\)
我们考虑转化一下:
\(\frac{m1}g*k1 \equiv \frac{c2-c1}g (mod\ \frac{m2}g)\)
当然,这个时候我们发现,\(\frac{c2-c1}g\)这条柿子一定要是整数,否则就有小数了,判断一下。
于是,现在我们已经去掉了一个k2了,但是左边依然很不优美,接下来考虑化简一波。
设\(ny()\)表示求逆元。
\(k1\equiv ny(\frac{m1}g)*\frac{c2-c1}g (mod\ \frac{m2}g)\)
\(k1=ny(\frac{m1}g)*\frac{c2-c1}g+\frac{m2}g*y\)
还记得这条柿子吗?
\(x=c1+m1*k1\)
于是我们把\(k1\)带回去
\(x=c1+ny(\frac{m1}g)*\frac{c2-c1}g*m1+\frac{m2*m1}g*y\)
去掉y就变成:
\(x \equiv c1+ny(\frac{m1}g)*\frac{c2-c1}g*m1 (mod\ \frac{m2*m1}g)\)
不就实现了合并吗?
然后逆元求解可以利用我们的拓展欧几里得。
当然要注意的一点是:小心爆longlong,可能需要用到龟速乘。

应用

例题:(最近做的一道)
Comet OJ - Contest #10 鱼跃龙门


怎么做?
考虑把某个n给分解质因数。
\(n=q_1^{p_1}*q_2^{p_2}*……*q_m^{p_m}\)
考虑m=1的情况:
x只可能是:\(y*q_m^{p_m}\)或是\(y*q_m^{p_m}-1\)
然后m的个数不可能超过12。
因此,我们考虑直接枚举每种质因子是\(y*q_m^{p_m}\)还是\(y*q_m^{p_m}-1\)。
然后联立方程式,利用拓展中国剩余定理求解即可。
时间复杂度:\(O(2^12*12*log)\)
然鹅这题比较逗比的是,用这种做法会爆longlong,然后就要打龟速乘。
而时间有很紧,因此要卡卡常。
这也是为什么我比赛T了17次没切的原因QWQ。

#include<bits/stdc++.h>
using namespace std;

int t;
long long zs[1000011],bz[1000011],p[1000011],flag[1000011];
long long n,x,y,gs,mi[21],m[21],c[21],ans;
bool bzz;

long long gcd(long long a,long long b)
{
    if (b==0) return a;
    else return gcd(b,a%b);
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
    if (b==0)
    {
        x=1;y=0;return a;
    }
    else
    {
        long long d=a/b;
        long long c=exgcd(b,a-b*d,x,y);
        long long z=x;
        x=y;y=z-d*y;
        return c;
    }
}
long long ny(long long a,long long b)
{
    long long z=exgcd(a,b,x,y);
    while (x<0)
    {
        x+=b;
    }
    return x;
}

long long cheng(long long a,long long b,long long mo)
{
    long long t=0;
    while(b)
    {
        t=(t+a*(b&1023))%mo;
        b>>=10;
        a=a*1024%mo;
    }
    return t;
}

#define R register
int main()
{
    mi[0]=1;
    for (int i=1;i<=20;i++)
    {
        mi[i]=mi[i-1]*2;
    }
    for (int i=2;i<=1000000;i++)
    {
        if (bz[i]==0)
        {
            zs[0]++;
            zs[zs[0]]=i;
            for (int j=1;j*i<=1000000;j++)
            {
                bz[j*i]=1;
            }
        }
    }
    scanf("%d",&t);
    while (t>0)
    {
        t--;
        scanf("%lld",&n);
        if (n==1)
        {
            printf("1\n");
            continue;
        }
        long long j=0;
        gs=0;
        flag[1]=0;
        for (int i=1;i<=zs[0];i++)
        {
            if (n%zs[i]==0)
            {
                gs++;
                p[gs]=1;
                if (zs[i]==2)
                {
                    flag[1]=1;
                }
            }
            while (n%zs[i]==0)
            {
                p[gs]=p[gs]*zs[i];
                n=n/zs[i];
            }
            if (zs[i]>n)
            {
                break;
            }
        }
        if (n>1)
        {
            gs++;
            p[gs]=n;
        }
        ans=20000000000000000;
        for (int i=1;i<=mi[gs]-1;i++)
        {
            long long j=i;
            memset(m,0,sizeof(m));
            memset(c,0,sizeof(c));
            int k=1;
            while (j>0)
            {
                if (flag[k]==1)
                {
                    m[k]=p[k]*2;
                }
                else m[k]=p[k];
                if (j%2==1)
                {
                    c[k]=m[k]-1;
                }
                else c[k]=0;
                k++;j=j/2;
            }
            for (int j=k;j<=gs;j++)
            {
                if (flag[j]==1)
                {
                    m[j]=p[j]*2;
                }
                else m[j]=p[j];
                c[j]=0;
            }
            bzz=true;
            for (R long long j=2;j<=gs;j++)
            {
                R long long m1(m[j-1]),m2(m[j])
                ,c1(c[j-1]),c2(c[j])
                ,T(gcd(m1,m2))
                ,mo(m2/T);
                if ((c2-c1)%T!=0)
                {
                    bzz=false;break;
                }
                m[j]=(m1*m2)/T;
                R long long op(ny(m1/T,mo)),oq(c2-c1),kk(ny(T,mo));
                if (op>1000000000 && oq>1000000000)
                c[j]=(cheng(oq,op,mo)*kk)%mo*m1+c1;
                else
                c[j]=(oq*kk%mo*op)%mo*m1+c1;

                c[j]=c[j]%m[j];
                if(c[j]<0)c[j]+=m[j];
            }
            if (bzz==true)
            {
                ans=min(ans,c[gs]);
            }
        }
        printf("%lld\n",ans);
    }
}

原文地址:https://www.cnblogs.com/RainbowCrown/p/11516820.html

时间: 2024-11-07 18:22:05

学习拓展中国剩余定理小结的相关文章

拓展中国剩余定理(exCRT)摘要

清除一个误区 虽然中国剩余定理和拓展中国剩余定理只差两个字,但他俩的解法相差十万八千里,所以会不会CRT无所谓 用途 求类似$$\begin{cases}x \equiv b_{1}\pmod{a_{1}} \\x \equiv b_{2}\pmod{a_{2}} \\...\\x \equiv b_{n}\pmod{a_{n}} \\ \end{cases}$$的线性同余方程组的解 具体过程 假设现在我们只有两个同余方程$$x \equiv b_{1}\pmod{a_{1}}$$ $$x \e

拓展中国剩余定理解决模数不互质同余方程组

如果模数互质的话,直接中国剩余定理就可以了 但是如果模数不互质又没有接触这个方法就凉凉了 推是很不好推出来的 假设我们这里有两个方程: x=a1?x1+b1 x=a2?x2+b2 a1,a2是模数,b1,b2是余数 那么我们可以合并这两个方程: a1?x1+b1=a2?x2+b2 由于x1和x2可以取负无穷到正无穷,所以符号不能约束它们,我们随便变一变形得到 a1?x1+a2?x2=b2?b1 然后使用拓展欧几里德算法,x和y分别是式子中的x1和x2 我们求出了一个最小正整数解x1 令k=(a1

中国剩余定理小结 (互质,非互质) (poj 1006,hdu 3579)

先证明下中国剩余定理 条件: x%m_1=a_1 x%m_2=a_2 ... x%m_n=a_n m_1,m_2,...,m_n两两互质 证明: 设M=m_1*m_2*m_3*...*m_n M_i=M/m_i 因为gcd(M_i,m_i)=1,所以M_ix+m_iy=1 (t_i*M_i)%m_i=1 //由Ext_gcd(M_i,m_i,x,y)求出,t_i=x 方程组的解:x=a_1*t_1*M_1+...+a_n*t_n*M_n 题目:poj 1006 http://poj.org/pr

拓展中国剩余定理(不互质的情况)

每次合并两个同余模方程,然后用exgcd解即可. ll LCM(ll a,ll b) { return a/__gcd(a,b)*b; } void exgcd(ll a,ll b,ll &d,ll &x,ll &y) { if(b==0){ x=1;y=0;d=a; return; } exgcd(b,a%b,d,y,x); y-=x*(a/b); } ll MLE(ll a,ll b,ll n) { ll x,y,d; exgcd(a,n,d,x,y); if(b%d) ret

excrt(拓展中国剩余定理)

对于一个同余方程 对于第一个和第二个式子 则有: ans=a1?+k1?∗n1? ans=a2?+k2?∗n2? 就有: a1?+k1?∗n1?=a2?+k2?∗n2? k1?∗n1?−k2?∗n2?=a2?−a1? 故我们设c=a2?−a1? 再变化一下形式就有: k1?∗n1?+(−k2?)∗n2?=c 令 gcd=gcd(n1?,n2?) 这样我们就可以通过exgcd来求出一组解x1?,y1? 满足 x1?∗n1?+y2?∗n2?=gcd 故:x1?∗d/g∗n1?+y2?∗d/g∗n2?

中国剩余定理讲解

中国剩余定理讲解 1.运用领域 扩展中国剩余定理是解决向下面列出的一元线性同余方程组的一种数论知识,可以求出下面方程组中最下的正整数$x$.但是扩展中国剩余定理和中国剩余定理有什么区别呢?中国剩余定理对于$mod$是有限制的,他对于$mod$要求为两两互质,然而扩展中国剩余定理对于$mod$没有要求. $\begin{cases} x\equiv x_1 (mod_1)\\ x\equiv x_2 (mod_2)\\ \ \ \ \ \ \ \vdots \ \ \ \ \ \ \ \ \ \

中国剩余定理及其拓展

中国剩余定理及其拓展 中国剩余定理CRT引例:(选自孙子兵法) 今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何? 怎么考虑这个问题? 按照题意: 设答案为x,则有 x≡2(mod 3) x≡3(mod 5) x≡2(mod 7) 就是求x的最小值 不难发现线性同余方程组的定义就是形如: x≡a1(mod m1) x≡a2(mod m2) x≡a3(mod m3) …………………………. x≡ak(mod mk) 的方程 Sol: 先看看解法:我们再来想想为什么是正确的. l 

中国剩余定理学习笔记

先看一道poj上的题目:[poj1006] Biorhythms 题意: 人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天.一个周期内有一天为峰值,在这一天,人在对应的方面(体力,情感或智力)表现最好.通常这三个周期的峰值不会是同一天.现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期.然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现. 分析: 首先我们要知道,任意两个峰值之间一定相距整数倍的周期.假设一年的第N天达到峰值,则下次达到峰值

[中国剩余定理]【学习笔记】

我会手写latex了哈哈哈O(∩_∩)O 终于会插入公式了,这样就可以去抄别人的公式啦 第一段直接抄zyf2000 第二段自己写的 求解同余方程请看 http://www.cnblogs.com/candy99/p/5765986.html Chinese Remainder Theorem 中国剩余定理 求解同余方程组 $x\equiv a_1\pmod {m_1}\\ $$x\equiv a_2\pmod {m_2} \\ $$x\equiv a_3\pmod {m_3}\\$$...\\$