码迷,mamicode.com
首页 > 其他好文 > 详细

常用数论

时间:2019-10-13 00:44:50      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:name   降幂   开平方   max   pre   coder   ace   stream   continue   

费马小定理

\(a^{p-1}\equiv1\pmod{m}\ (p是质数)\)

求逆元

方法一:扩展欧几里得算法
前提:\(a\)\(p\)互质
原理:\(a*x\equiv1\pmod{p} \\ 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}\equiv1\pmod{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\n");
        else printf("%lld\n",r1);
    }
    return 0;
}


欧拉函数

欧拉函数是小于x的整数中与x互质的数的个数,一般用\(\varphi(x)\)表示。特殊的,\(\varphi(1)=1\)
通式:\(\varphi(x)=x\prod_{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]];//利用了欧拉函数是个积性函数的性质 
        }
    }
}


欧拉降幂

\[\begin{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\n",ans%mod);
    }
    return 0;
}


二次剩余

对于\(p,n\),若存在整数\(x\),满足\(x^2\equiv n\pmod{p}\),则称\(n\)为模\(p\)意义下的二次剩余
用人话说就是\(n\)在模\(p\)意义下是否能开方
勒让德符号定义如下:
\[(\frac{n}{p})=\begin{cases}1 ,& n在模p意义下是二次剩余 \\ -1,& n在模p意义下非二次剩余 \\ 0,& n\equiv0\pmod{p}\end{cases}\]
对于勒让德符号,有
\[(\frac{n}{p})\equiv n^{\frac{p-1}{2}}\pmod{p}(p为奇素数)\]
定理一:\[n^2\equiv(p-n)^2\pmod{p}\]
定理二:\(p\)的二次剩余和二次非剩余的1个数均为\(\frac{p-1}{2}\)(不考虑0的情况下)

例题:https://ac.nowcoder.com/acm/contest/889/B
题意:已知\(x+y\equiv b\pmod{p} \\ x*y\equiv c\pmod{p}\),求\(x,y\)
思路:\((x-y)^2\equiv b^2-4c\pmod{p}\)
\(a=b^2-4c\),由二次剩余定理可得:\(a^{\frac{p-1}{2}}\equiv 1\pmod{p}\)
两边同时乘\(a\),可得:\(a^{\frac{p+1}{2}}\equiv a\pmod{p}\)
\((x-y)^2\equiv a^{\frac{p+1}{2}}\pmod{p}\)
开平方:\(x-y\equiv a^{\frac{p+1}{4}}\pmod{p}\)
\(x+y\equiv b\pmod{p}\)与上式相加可得:\(2x\equiv 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\n",b/2,b/2);//b*b=4*c;
            continue;
        }
        if(qpow(d,(p-1)/2)!=1)
        {
            printf("-1 -1\n");
            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\n",min(x,y),max(x,y));
    }
    return 0;
}


类欧几里得

用于求解\[\sum_{i=0}^n\lfloor\frac{ai+b}{c}\rfloor,\sum_{i=0}^n\lfloor\frac{ai+b}{c}\rfloor^2,\sum_{i=0}^ni\lfloor\frac{ai+b}{c}\rfloor\]这样的式子
模板题: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\n",(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=2a\cdot f_{n-1}+(b-a^2)\cdot f_{n-2}\)

常用数论

标签:name   降幂   开平方   max   pre   coder   ace   stream   continue   

原文地址:https://www.cnblogs.com/HooYing/p/11437277.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!