ACM数论板子


未完 待补。

推荐博客:

[总结]数论和组合计数类数学相关(定理&证明&板子)
[总结]其他杂项数学相关(定理&证明&板子)
总结]多项式类数学相关(定理&证明&板子)
[探究] OI中各种初级数论算法相关

板子:

慢速乘

在模数较大的情况下,防止爆long longlong\ long

ll qmul(ll a,ll b,ll p)
{
    ll ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%p;
        a<<=1;
        a%=p;
        b>>=1;
    }
    return ans;
}

快速乘

目的同上,但是时间复杂度是O(1)O(1)的。(精度出锅自己负责~ )

ll fmul(ll a,ll b,ll p)
{
    return (a*b-(ll)((long double)a*b/p)*p+p)%p;
}

快速幂

ll qpow(ll a,ll b)
{
    ll t1=a,t2=1;
    while(b)
    {
        if(b&1)
            t2=t2*t1%p;
        t1=t1*t1%p;
        b>>=1;
    }
    return t2;
}

矩阵快速幂

原理和快速幂一样,只不过需要自己构造矩阵、实现矩阵乘法,给一个样例吧。

struct Matrix
{
	ll t[3][3];
	Matrix()
	{
		t[0][0]=t[0][1]=t[2][0]=t[2][2]=1;
		t[1][0]=2;
		t[0][2]=t[1][1]=t[1][2]=t[2][1]=0;
	}
};

Matrix mul(Matrix a,Matrix b)
{
	Matrix c;
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			c.t[i][j]=0;
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			for(int k=0;k<3;k++)
				c.t[i][j]=(c.t[i][j]+a.t[i][k]*b.t[k][j])%m;
	return c;
}

Matrix qpow(ll b)
{
	Matrix t1,t2;
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
		{
			t1.t[i][j]=(i==j?1:0);
		}
	while(b>0)
	{
		if(b&1)
			t1=mul(t1,t2);
		t2=mul(t2,t2);
		b>>=1;
	}
	return t1;
}

GCDGCD

int gcd(int a, int b) 
{
     return b == 0 ? a : gcd(b, a%b);
} 

EXGCDEXGCD

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

tipax+by=gcd(a,b)tip:a*x+b*y=gcd(a,b),当apa、p互质时,想要求aapp的乘法逆元,只需要调用exgcd(a,p,x,y)exgcd(a,p,x,y),求得的xx即为答案。(xx可能是个负数,需要注意一下)

乘法逆元

普通的乘法逆元的求法如上,这里只提一下逆元的线性算法。

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

const int maxn=3e6+5;

int n,p;
int inv[maxn]; //inv[i] 表示 i 模 p 的乘法逆元

void work()//求出 1-n 所有数在模 p 意义下的乘法逆元 要保证p是一个素数且 n<p
{
    inv[1]=1;
    for(int i=2;i<=n;i++)
    {
        inv[i]=(ll)-(p/i)*inv[p%i]%p;
        if(inv[i]<0)
            inv[i]+=p;
    }
}

int main()
{
    scanf("%d %d",&n,&p);
    work();
    for(int i=1;i<=n;i++)
        printf("%d\n",inv[i]);
    return 0;
}

RCTRCT

ll qmul(ll a,ll b,ll p)
{
    ll ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%p;
        a<<=1;
        a%=p;
        b>>=1;
    }
    return ans;
}

ll fmul(ll a,ll b,ll p)
{
    return (a*b-(ll)((long double)a*b/p)*p+p)%p;
}

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

ll inv(ll a,ll p)// 求 a%p 的乘法逆元
{
    ll x,y;
    exgcd(a,p,x,y);
    return (x%p+p)%p;
}

ll RCT()
{
    ll ans=0,M=1;
    for(int i=1;i<=n;i++)
        M*=m[i];
    for(int i=1;i<=n;i++)
    {
        ll tmp=M/m[i];
        ans=(ans+fmul(fmul(a[i],tmp,M),inv(tmp,m[i]),M))%M;
    }
    return (ans+M)%M;
}

EXRCTEXRCT

ll EXRCT()
{
    ll ans=a[1],M=m[1];
    ll x,y,gcd;
    for(int i=2;i<=n;i++)
    {
        gcd=exgcd(M,m[i],x,y); // M * x + m[i] * y = gcd(M,m[i])
        ll t1=((a[i]-ans)%m[i]+m[i])%m[i];
        ll t2=m[i]/gcd;
        if(t1%gcd!=0)
            return -1; //无解
        x=fmul(x,t1/gcd,t2);
        ans+=x*M;
        M*=t2;
        ans=(ans%M+M)%M;
    }
    return ans;

}
发布了638 篇原创文章 · 获赞 24 · 访问量 3万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 撸撸猫 设计师: 设计师小姐姐

分享到微信朋友圈

×

扫一扫,手机浏览