zoukankan      html  css  js  c++  java
  • 数论知识点总结(noip范围)

    数论知识点:

    约数个数和约数和公式(例题:POJ1845 分治思想):

    质因数分解 p1^k1xp2^k2xp3^k3...pn^kn

    约数个数和(1+k1)(1+k2)...(1+kn)

    所有约数和=(1+p1+p1^2+...+p1^k1)...(1+pn+pn^2+...+pn^kn)

    求和方法:因式分解+分治

                或者等比数列求和+拓展GCD求逆元

    欧拉定理:若GCD(x,y)≡1,则x^(φ(y))≡1(mode y)

          特殊:费马小定理:若y是质数,且x,y互质,则x^(y-1)≡1 (mode y)

    推论:降幂公式:若GCD(x,y)≡1,则a^x≡a^(x%φ(y))(mode y)

                若GCD(x,y)≠ 1,则a^x≡a^(x%φ(y)+φ(y))(mode y)

    欧拉函数φ(x),其中若x为质数,则φ(x)=x-1,且欧拉函数为积性函数(人话:可以线性筛!!!

    gcd与lcmGCD(x,y)xLCM(x,y)=xy

    拓展GCDax≡y (mod p)

    刚刚写计算器,发现我对拓展gcd的理解出现了漏洞......

    (我发现我忽略了使用拓展gcd的第一步,上来就递归......)

    使用拓展gcd步骤如下:

                    给定不定方程ax≡y(mode p)
                    首先求gcd(a,p)=t    ①
                    若y mode t !=0,则原方程无整数解
                    若y mode t = 0,则:
                    a/=t,y/=t,p/=t   ②
                    即将原方程化为a0x+p0z=y0的形式
                    接下来求出a0x+p0z=1  ③的一组整数解x0,z0
                    此时才用到拓展gcd
                    其解法:辗转相除至b=0,此时赋值x=1,y=0,回溯时修改x=y0,y=x0-(a/b)y0
                    然后再算出x=y0*x0+kp0(k∈Z)
                              z=y0*z0+kp0(k∈Z)  ④
                    最后化出正整数(取模加模再取模)即可  ⑤
                    所以拓展gcd是至少有5步的!
                    (然而我只记得辗转相除再赋值...所以计算器WA了一下午...)

    求逆元:拓展GCD,费马-欧拉定理,线性筛

    中国剩余定理:已知

                x%a0≡a1,x%b0≡b1,x%c0≡c1
    
                令M1=b0xc0,M2=a0xc0,M3=a0xb0
    
                则原方程可变为:
    
                M1x1≡1(mode a0)
    
                M2x2≡1(mode b0)
    
                M3x3≡1(mode c0)
    
                显然可用拓展gcd解出x1,x2,x3
    
                那么,所求x=(M1a1x1+M2a2x2+M3a3x3)%(LCM(a0,b0,c0))

    结论:中国剩余定理给出了一系列模方程组,可以采用拓展GCD将上述方程拓展到n个,采用拓展gcd解之即可

    通解: 对于x%a0≡b0...等一系列方程组

                我们可以令M=Πai
    
                对于每一个xi,求出Mixi≡1(mode ai)的xi
    
                其中Mi=M/ai
    
                则最终所求的x=Σ(Mibixi)%M
    
                例:曹冲养猪

    线性筛:线性筛可以筛:

                素数+欧拉函数:
    
                void eular()
                {
                    for(int i=2;i<=maxN;i++)
                    {
                        if(used[i]==0)
                        {
                            prime[++cnt]=i;
                            phi[i]=i-1;
                        }
                        for(int j=1;j<=cnt&&i*prime[j]<=maxN;j++)
                        {
                            used[i*prime[j]]=1;
                            if(i%prime[j]==0)
                            {
                                phi[i*prime[j]]=phi[i]*prime[j];
                                break;
                            }else
                            {
                                phi[i*prime[j]]=phi[i]*(prime[j]-1);
                            }
                        }
                    }
                }
    
                素数+约数个数:
    
                void make(int n)//线性筛 
                {
                    f[1]=1;//初值 
                    for(int i=2;i<=n;i++)
                    {
                        if(used[i]==0)//未被标记 
                        {
                            f[i]=2;//该数为素数 
                            p[++cnt]=i;
                            d[i]=1;//该数最大次数为1 
                        }
                        for(int j=1;j<=cnt&&i*p[j]<=n;j++)
                        {
                            used[i*p[j]]=1;//打标记 
                            if(i%p[j]==0)//该数中有这一质因子 
                            {
                                f[i*p[j]]=f[i]/(d[i]+1)*(d[i]+2);//此二数之积的因数个数应为其中一数的因数个数再多一个该质数 
                                d[i*p[j]]=d[i]+1;//最小质因子最高次幂就是其加上1 
                                break;
                            }
                            f[i*p[j]]=f[i]*2;//搞定 
                            d[i*p[j]]=1;
                        }
                    }
                }
    
                对模mode的逆元:
    
                void init()
                {
                    inv[1]=1;
                    for(int i=2;i<=maxn;i++)
                    {
                        inv[i]=(mode-mode/i)*inv[mode%i]%mode;    
                    }
                    inv[0]=1;
                    for(int i=1;i<=maxn;i++)
                    {
                        inv[i]=inv[i-1]*inv[i]%mode;
                    }
                    jiecheng[1]=1;
                    for(int i=2;i<=maxn;i++)
                    {
                        jiecheng[i]=jiecheng[i-1]*i%mode;
                    }
                }

    以及混合起来的万能筛:

     #include <cstdio>
                                            #define mode 998244353
                                            #define maxn 1000000
                                            using namespace std;
                                            bool used[1000006];
                                            int prime[1000006];//素数
                                            int fac[1000006];//约数个数
                                            int mi[1000006];//约数的最高次幂
                                            int inv[1000006];//对mode的逆元
                                            int phi[1000006];//欧拉函数
                                            int cnt=0;
                                            void init()
                                            {
                                                inv[0]=1;
                                                inv[1]=1;
                                                fac[1]=1;
                                                for(int i=2;i<=maxn;i++)
                                                {
                                                    inv[i]=(mode-mode/i)*inv[mode%i]%mode;
                                                    if(!used[i])
                                                    {
                                                        prime[++cnt]=i;
                                                        fac[i]=2;
                                                        mi[i]=1;
                                                        phi[i]=i-1;
                                                    }
                                                    for(int j=1;j<=cnt&&i*prime[j]<=maxn;j++)
                                                    {
                                                        used[i*prime[j]]=1;
                                                        if(i%prime[j]==0)
                                                        {
                                                            fac[i*prime[j]]=fac[i]/(mi[i]+1)*(mi[i]+2);
                                                            mi[i*prime[j]]=mi[i]+1;
                                                            phi[i*prime[j]]=phi[i]*prime[j];
                                                            break;
                                                        }
                                                        phi[i*prime[j]]=phi[i]*phi[prime[j]];
                                                        fac[i*prime[j]]=fac[i]*2;
                                                        mi[i*prime[j]]=1;
                                                    }
                                                }
                                            }
                                            int main()
                                            {
                                                init();
                                                for(int i=1;i<=cnt;i++)
                                                {
                                                    printf("%d
    ",prime[i]);
                                                }
                                                return 0;
                                            }
  • 相关阅读:
    服务器与本地时间的倒计时
    没有花括号(大括号)的for循环也能正确执行
    js瀑布流效果
    AQS详解(AbstractQueuedSynchronizer)
    SimpleDateFormat的线程安全问题与解决方案
    jvm不打印异常栈
    Java中的序列化Serialable高级详解
    java梳理-序列化与反序列化
    AQS详解
    对ConditionQueue和锁的理解
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10764219.html
Copyright © 2011-2022 走看看