zoukankan      html  css  js  c++  java
  • 常用数论

    费马小定理

    (a^{p-1}equiv1pmod{m} (p是质数))

    求逆元

    方法一:扩展欧几里得算法
    前提:(a)(p)互质
    原理:(a*xequiv1pmod{p} quad a*x+p*y=1)
    (x)就是我们要求的逆元

    LL exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得算法 
    {
        if(b==0)
        {
            x=1,y=0;
            return a;
        }
        LL ret=exgcd(b,a%b,y,x);
        y-=a/b*x;
        return ret;
    }
    LL getInv(int a,int mod)//求a在mod下的逆元,不存在逆元返回-1 
    {
        LL x,y;
        LL d=exgcd(a,mod,x,y);
        return d==1?(x%mod+mod)%mod:-1;
    }
    

    方法二:费马小定理
    前提:(a)(p)互质且(p)为素数
    原理:(a^{p-1}equiv1pmod{p} (p是质数) \ inv(a)=a^{p-2}pmod{p})


    中国剩余定理

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long LL;
    LL exgcd(LL a,LL b,LL &x,LL &y)
    {
        if(b==0)
        {
            x=1;y=0;return a;
        }
        LL d=exgcd(b,a%b,y,x);
        y-=a/b*x;
        return d;
    }
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
            int flag=0;
            LL a1,r1,a2,r2,x,y;
            scanf("%lld%lld",&a1,&r1);
            for(int i=1;i<n;i++)
            {
                scanf("%lld%lld",&a2,&r2);
                LL c=r2-r1;
                LL d=exgcd(a1,a2,x,y);//a1*x+a2*y=gcd(a1,a2)
                if(c%d)flag=1;
                LL x0=c/d*x;//a1*(c/d*x)+a2(c/d*y)=c
                LL t=a2/d;
                x0=(x0%t+t)%t;//求a1*x0+a2*y0=c的x0的最小解(x0有可能是负数)
                r1=r1+a1*x0;
                a1=a1/d*a2;
            }
            if(flag)printf("-1
    ");
            else printf("%lld
    ",r1);
        }
        return 0;
    }
    

    欧拉函数

    欧拉函数是小于x的整数中与x互质的数的个数,一般用(varphi(x))表示。特殊的,(varphi(1)=1)
    通式:(varphi(x)=xprod_{i=1}^n (1-frac{1}{p_i}))

    埃拉托斯特尼筛求欧拉函数

    void euler(int n)
    {
        for (int i=1;i<=n;i++) phi[i]=i;
        for (int i=2;i<=n;i++)
        {
            if (phi[i]==i)//这代表i是质数
            {
                for (int j=i;j<=n;j+=i)
                {
                    phi[j]=phi[j]/i*(i-1);//把i的倍数更新掉
                }
            }
        }
    }
    

    欧拉筛求欧拉函数

    void euler(int n)
    {
    	phi[1]=1;//1要特判 
    	for (int i=2;i<=n;i++)
    	{
    		if (flag[i]==0)//这代表i是质数 
    		{
    			prime[++num]=i;
    			phi[i]=i-1;
    		}
    		for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法 
    		{
    			flag[i*prime[j]]=1;//先把这个合数标记掉 
    			if (i%prime[j]==0)
    			{
    				phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子 
    				break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次 
    			}
    			else phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质 
    		}
    	}
    }
    

    欧拉降幂

    [egin{cases}A^Bmod(C)=A^{Bmod(phi(C))}modC (B< phi(C)) \ A^Bmod(C)=A^{Bmod(phi(C))+phi(C)}modC (B>= phi(C))end{cases}]

    例题:求幂塔函数(a^{a^{a^{...}}}pmod{p})
    题解:用递归+欧拉降幂去求

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxx = 1e6+10;
    LL phi[maxx];
    void euler()
    {
        for(int i=1;i<maxx;i++)phi[i]=i;
        for(int i=2;i<maxx;i++)
        {
            if(phi[i]==i)//这代表i是质数
            {
                for(int j=i;j<=maxx;j+=i)
                {
                    phi[j]=phi[j]/i*(i-1);//把i的倍数更新掉
                }
            }
        }
    }
    LL quick(LL a,LL b,LL mod)
    {
        LL res=1;
        while(b)
        {
            if(b&1)res=(res*a)%mod;
            b>>=1;
            a=(a*a)%mod;
        }
        return res;
    }
    LL solve(LL a,LL b,LL p)
    {
        if(p==1)return 0;
        if(b==0)return 1;
        LL t=solve(a,b-1,phi[p]);
        if(t<phi[p]&&t)return quick(a,t,p);
        else return quick(a,t+phi[p],p);
    }
    int main()
    {
        euler();
        int T;
        cin>>T;
        while(T--)
        {
            LL a,b,mod;
            scanf("%lld%lld%lld",&a,&b,&mod);
            LL ans=solve(a,b,mod);
            printf("%lld
    ",ans%mod);
        }
        return 0;
    }
    

    二次剩余

    对于(p,n),若存在整数(x),满足(x^2equiv npmod{p}),则称(n)为模(p)意义下的二次剩余
    用人话说就是(n)在模(p)意义下是否能开方
    勒让德符号定义如下:

    [(frac{n}{p})=egin{cases}1 ,& n在模p意义下是二次剩余 \ -1,& n在模p意义下非二次剩余 \ 0,& nequiv0pmod{p}end{cases} ]

    对于勒让德符号,有

    [(frac{n}{p})equiv n^{frac{p-1}{2}}pmod{p}(p为奇素数) ]

    定理一:$$n2equiv(p-n)2pmod{p}$$
    定理二:(p)的二次剩余和二次非剩余的1个数均为(frac{p-1}{2})(不考虑0的情况下)

    例题:https://ac.nowcoder.com/acm/contest/889/B
    题意:已知(x+yequiv bpmod{p} \ x*yequiv cpmod{p}),求(x,y)
    思路:((x-y)^2equiv b^2-4cpmod{p})
    (a=b^2-4c),由二次剩余定理可得:(a^{frac{p-1}{2}}equiv 1pmod{p})
    两边同时乘(a),可得:(a^{frac{p+1}{2}}equiv apmod{p})
    ((x-y)^2equiv a^{frac{p+1}{2}}pmod{p})
    开平方:(x-yequiv a^{frac{p+1}{4}}pmod{p})
    (x+yequiv bpmod{p})与上式相加可得:(2xequiv b+a^{frac{p+1}{4}}pmod{p})
    (x=inv(2)(b+a^{frac{p+1}{4}})pmod{p})

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    LL p=1e9+7;
    LL qpow(LL a,LL b)
    {
        LL res=1;
        while(b)
        {
            if(b&1)res=res*a%p;
            a=a*a%p;
            b>>=1;
        }
        return res;
    }
    int main()
    {
        int t;
        cin>>t;
        LL b,c;
        while(t--)
        {
            scanf("%lld%lld",&b,&c);
            LL d=b*b-4*c;
            d=(d+p)%p;//避免负数
            if(d==0)
            {
                printf("%lld %lld
    ",b/2,b/2);//b*b=4*c;
                continue;
            }
            if(qpow(d,(p-1)/2)!=1)
            {
                printf("-1 -1
    ");
                continue;
            }
            LL x=(b+qpow(d,(p+1)/4))%p*qpow(2,p-2)%p;
            LL y=b-x;
            y=(y+p)%p;
            printf("%lld %lld
    ",min(x,y),max(x,y));
        }
        return 0;
    }
    

    类欧几里得

    用于求解$$sum_{i=0}^n lfloor frac{ai+b}{c} floor,sum_{i=0}^n lfloorfrac{ai+b}{c} floor^2 ,sum_{i=0}^n ilfloorfrac{ai+b}{c} floor$$这样的式子
    模板题:https://www.luogu.org/problem/P5170
    这篇博客讲的很详细:https://www.luogu.org/blog/shiqingyu/solution-p5170
    直接去求的话代码如下,但因为重复计算而太耗时,所以可以用个结构体保留三者的结果

    LL f(LL a,LL b,LL c,LL n) //第一条式子
    {
        if(a==0)return (n+1)*(b/c)%mod;
        if(n==0)return b/c;
        if(a>=c||b>=c)return (f(a%c,b%c,c,n)+(a/c)*n%mod*(n+1)%mod*inv2%mod+(b/c)*(n+1)%mod)%mod;
        LL m=(a*n+b)/c;
        return (n*m%mod-f(c,c-b-1,a,m-1))%mod;
    }
    LL g(LL a,LL b,LL c,LL n) //第三条式子
    {
        if(a==0)return (b/c)*n%mod*(n+1)%mod*inv2%mod;
        if(n==0)return 0;
        if(a>=c||b>=c)return (g(a%c,b%c,c,n)+(a/c)*n%mod*(n+1)%mod*(2*n+1)%mod*inv6%mod+(b/c)*n%mod*(n+1)%mod*inv2%mod)%mod;
        LL m=(a*n+b)/c;
        return (n*(n+1)%mod*m%mod-f(c,c-b-1,a,m-1)-h(c,c-b-1,a,m-1))%mod*inv2%mod;
    }
    LL h(LL a,LL b,LL c,LL n) //第二条式子
    {
        if(a==0)return (n+1)*(b/c)%mod*(b/c)%mod;
        if(n==0)return (b/c)*(b/c)%mod;
        if(a>=c||b>=c)return (h(a%c,b%c,c,n)+(a/c)*(a/c)%mod*n%mod*(n+1)%mod*(2*n+1)%mod*inv6%mod+(b/c)*(b/c)%mod*(n+1)%mod+(a/c)*(b/c)%mod*n%mod*(n+1)%mod+2*(a/c)%mod*g(a%c,b%c,c,n)%mod+2*(b/c)%mod*f(a%c,b%c,c,n)%mod)%mod;
        LL m=(a*n+b)/c;
        return (n*m%mod*(m+1)%mod-2*g(c,c-b-1,a,m-1)-2*f(c,c-b-1,a,m-1)-f(a,b,c,n))%mod;
    }
    
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int mod = 998244353;
    const LL inv2 = 499122177;
    const LL inv6 = 166374059;
    struct node
    {
        LL f,g,h;
    };
    node solve(LL a,LL b,LL c,LL n)
    {
        node ans,tmp;
        if(a==0)
        {
            ans.f=(n+1)*(b/c)%mod;
            ans.g=(b/c)*n%mod*(n+1)%mod*inv2%mod;
            ans.h=(n+1)*(b/c)%mod*(b/c)%mod;
            return ans;
        }
        if(a>=c||b>=c)
        {
            tmp=solve(a%c,b%c,c,n);
            ans.f=(tmp.f+(a/c)*n%mod*(n+1)%mod*inv2%mod+(b/c)*(n+1)%mod)%mod;
            ans.g=(tmp.g+(a/c)*n%mod*(n+1)%mod*(2*n+1)%mod*inv6%mod+(b/c)*n%mod*(n+1)%mod*inv2%mod)%mod;
            ans.h=(tmp.h+(a/c)*(a/c)%mod*n%mod*(n+1)%mod*(2*n+1)%mod*inv6%mod+(b/c)*(b/c)%mod*(n+1)%mod+(a/c)*(b/c)%mod*n%mod*(n+1)%mod+2*(a/c)%mod*tmp.g%mod+2*(b/c)%mod*tmp.f%mod)%mod;
            return ans;
        }
        LL m=(a*n+b)/c;
        tmp=solve(c,c-b-1,a,m-1);
        ans.f=(n*m%mod-tmp.f)%mod;
        ans.g=(n*(n+1)%mod*m%mod-tmp.f-tmp.h)%mod*inv2%mod;
        ans.h=(n*m%mod*(m+1)%mod-2*tmp.g-2*tmp.f-ans.f)%mod;
        return ans;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        LL n,a,b,c;
        while(t--)
        {
            scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
            node ans=solve(a,b,c,n);
            printf("%lld %lld %lld
    ",(ans.f+mod)%mod,(ans.h+mod)%mod,(ans.g+mod)%mod);
        }
        return 0;
    }
    

    斐波那契相关公式

    (f_n=f_{n-1}+f_{n-2}(n>=2))
    (f_n-f_{n-1}-f_{n-2}=0)
    (f_n=q^n)
    (q^n-q^{n-1}-q^{n-2}=0)
    (q^{n-2}(q^2-q-1)=0)
    故求解(q^2-q-1=0)的解
    (q_1=frac{1+sqrt{5}}{2},q_2=frac{1-sqrt{5}}{2})
    因为非波那契递推关系是线性的且齐次,所以对于任选常数(c_1,c_2)
    (f_n=c_1(frac{1+sqrt{5}}{2})^n+c_2(frac{1-sqrt{5}}{2})^n)
    随便代入两个n的数求解就行
    解得斐波那契通项公式:(f_n=frac{1}{sqrt{5}}(frac{1+sqrt{5}}{2})^n-frac{1}{sqrt{5}}(frac{1-sqrt{5}}{2})^n)
    故求解形如((a+sqrt{b})^n)的式子
    我们会联想到斐波那契通项公式,因此构造数列
    (f_n=(a+sqrt{b})^n+(a-sqrt{b})^n)
    (f_n=p*f_{n-1}+q*f_{n-2})
    故求解(f_2-pf-q=0)的解
    我们已经知道方程的两个解(f_1=a+sqrt{b},f_2=a-sqrt{b})
    带入求解p,q,最后得到(p=2a,q=b-a^2)
    因此我们得到了递推式:(f_n=2acdot f_{n-1}+(b-a^2)cdot f_{n-2})

  • 相关阅读:
    linux挂载windows共享文件夹
    centos-6.7 内核升级(转)
    关闭系统邮件提醒:you hava a new mail(转)
    2016年国内开源镜像站点汇总(转)
    RedHat/Fedora/Centos 下bash 自动补全命令
    shell死循环脚本示例
    查看http的并发请求数与其TCP连接状态
    (十二)微信小程序实现登陆页面+登陆逻辑
    vue实现登陆单页面
    vue前端项目初始化的步骤
  • 原文地址:https://www.cnblogs.com/HooYing/p/11437277.html
Copyright © 2011-2022 走看看