数论基础(浅谈数论的部分实现)

最近写到一些基础数论题,
发现一个可怕的事实
基础数论的理论我都懂,但是连最基础的板子都有可能敲错
所以特意停下手中的题,进行基础数论的实现

First.欧几里得(辗转相除)

int gcd(int a,int b)
{
    int r=a%b;
    while (r)
    {
        a=b;b=r;r=a%b;
    }
    return b;
}

Second.扩展欧几里得

ax+by=gcd(a,b)
ax+by=bx’+(a%b)y’
ax+by=bx’+(a-(a/b)*b)y’
ax+by=ay’+b(x’-(a/b)y’)

x=y’
y=x’-(a/b)y’

使用条件

等号右边一定是gcd(a,b)*k (k!=0)
如果是求拟元,则gcd(a,b)==1

int exgcd(int a,int b)
{
    if (b==0)
    {
        x=1;y=0;
        return;
    }
    else
    {
        exgcd(b,a%b);
        int t=y;
        y=x-(a/b)*y;
        x=t;
    }
}

Third.KSM+费马小定理

使用条件

a,p互质

ll KSM(ll a,int b,ll p)
{
    ll t=1;
    a%=p;
    while (b)
    {
        if (b&1)
           t=(t%p*a%p)%p;
        b>>=1;
        a=(a%p*a%p)%p;
    }
    return t%p;
}

ll fm(ll x,ll p)
{
    return KSM(x,p-2,p);
}

Forth.线性求拟元
a在mod p意义下的拟元
p%a=p-(p/a)*a
p%a=-(p/a)*a
a=(p%a)*(-p/a)^-1
a^-1=inv[p%a]*(p-p/a)

int inv[N];

void INV(int n,int p)
{
    inv[0]=0;
    inv[1]=1;
    for (int i=2;i<=n;i++)
        inv[i]=(p-(p/i))*inv[p%i]%p;
}

Fifth.bsgs

map<ll,int> mp;

int bsgs(ll x,ll z,ll p)
{
    x%=p; z%=p;
    mp.clear();
    if (x==0&&z==0) return 0;
    if (x==0) return -1;
    ll m=(ll)ceil(sqrt((double)p)),now=1;
    mp[1]=m+1;
    for (int i=1;i<m;i++)
    {
        now=(now%p*x%p)%p;
        if (!mp[now]) mp[now]=i;
    }
    ll inv=1,tmp=KSM(x,p-m-1,p);
    for (int k=0;k<m;k++)
    {
        int i=mp[(z%p*inv%p)%p];
        if (i)
        {
            if (i==m+1) i=0;
            return k*m+i;
        }
        inv=(inv%p*tmp%p)%p;
    }
    return -1;
}

Sixth.组合数的递推

int C[N][N];

void doit(int n,int m)
{
    int i,j;
    C[1][1]=1;
    for (i=2;i<=n;i++)
        for (j=1;j<=i;j++)
            C[i][j]=C[i-1][j]+C[i-1][j-1];
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=i;j++)
            printf("%d ",C[i][j]);
        puts("");
    }
}

Seventh.Lucas

使用条件

p模数是素数
相当于把n,m变成p进制数
C组合数可以预处理
因为p是质数,所以可以用费马小定理求拟元,
当然如果预处理了C就没有这个问题了

int inv(int x,int p)
{
    return KSM(x,p-2,p);
}

int C(int n,int m)
{
    if (m>n) return 0;
    int FZ=1,FM=1;
    for (int i=n-m+1;i<=n;i++) FZ=(FZ*i)%p;
    for (int i=2;i<=m;i++) FM=(FM*i)%p;
    return (FZ%p*inv(FM,p)%p)%p;
}

int Lucas(int n,int m,int p)
{
    if (n<m) return 0;
    int ans=1;
    while (m)
    {
        ans=(ans%p*C(n%p,m%p)%p)%p;
        n/=p;
        m/=p;
    }
    return ans;
}

Eighth.线性筛素数

int sshu[N],tot=0;
bool no[N];

void make(int n)
{
    memset(no,0,sizeof(no));
    for (int i=2;i<=n;i++)
    {
        if (!no[i])
           sshu[++tot]=i;
        for (int j=1;j<=tot&&sshu[j]*i<=n;j++)
        {
            no[sshu[j]*i]=1;
            if (i%sshu[j]==0) break;   //i%sshu[j] 
        }
    }
}

Ninth.欧拉函数(phi)
计算式:
phi(i)=i*∏((j-1)/j) {j是素数且i%j==0}

注意

先除后乘防止炸掉

int phi[N];

void makephi(int n)   //phi[i]小于等于i且与i互质的数的个数 
{
    int i,j;
    for (i=1;i<=n;i++) phi[i]=i;
    for (i=1;i<=tot&&sshu[i]<=n;i++)
        for (j=sshu[i];j<=n;j+=sshu[i])
        {
            phi[j]=phi[j]/sshu[i];
            phi[i]=phi[j]*(sshu[i]-1);
        } 
}

Tenth.莫比乌斯函数(mu)
μ(1)=1;
μ(素数)=-1
μ(分解质因数后,每个质因子<=1个)=-1^(质因子个数);
μ(其他)=0

莫比乌斯函数完整定义的通俗表达:
1)莫比乌斯函数μ(n)的定义域是N
2)μ(1)=1
3)当n存在平方因子时,μ(n)=0
4)当n是素数或奇数个不同素数之积时,μ(n)=-1
5)当n是偶数个不同素数之积时,μ(n)=1

void makemu(int n)
{
    mu[1]=1;
    memset(no,0,sizeof(no));
    for (int i=1;i<=n;i++)
    {
        if (!no[i])
        {
            sshu[++tot]=i;
            mu[i]=-1;
        }
        for (int j=1;j<=tot&&sshu[j]*i<=n;j++)
        {
            no[sshu[j]*i]=1;
            if (i%sshu[j]==0)
            {
                mu[i*sshu[j]]=0;
                break;
            }
            mu[i*sshu[j]]=-mu[i];
        }
    }
}

转载于:https://www.cnblogs.com/wutongtong3117/p/7673243.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值