数论模板

1.求gcd

利用性质 gcd(a,b)=gcd(b,a%b)

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

LL gcd(LL a,LL b)
{
    if (a==0) return 1;
    if(a<0) return gcd(-a,b);
    while(b)
    {
        LL t=a%b;
        a=b;
        b=t;
    }
    return a;
}   //  允许负数 

 

2.快速幂

不再赘述

ll pow(ll a,ll b,ll mode) {
	ll sum=1;
	while (b) {
		if (b&1) {
			sum=(sum*a) % mode;
			b--;
		}
		b/=2;
		a=a*a%mode;
	}
	return sum;
}

 

3.扩展欧几里得

用于计算ax+by=gcd(a,b)的一组解

只要我们找到一组特殊的解 x0 和 y0,那么,我们就可以用 x0 和 y0 表示出整个不定方程的通解:

x = x0 + (b/gcd)*t

y = y0 – (a/gcd)*t

扩欧的具体操作是这样的

当前方程

ax+by=gcd

递归解的下一个方程

bx'+(a%b)y'=gcd

而 a%b = a - (a/b)*b

这样我们可以解得一个关系

x=f(x',y'),y=g(x',y')

然后递归回溯即可

扩欧的作用

可以计算出逆元

ax = 1(mod m)

这里,我们称 x 是 a 关于 m 的乘法逆元

可以等价于这样的表达式: a*x + m*y = 1,然后用扩欧就解决了

LL ex_gcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    LL ans=ex_gcd(b,a%b,x,y);
    LL temp=x;
    x=y;
    y=temp-a/b*y;
    return ans;
}
 
LL cal(LL a,LL b,LL c)
{
    LL x,y;
    LL gcd = ex_gcd(a,b,x,y);
    if (c%gcd != 0) return -1;
    x*=c/gcd;
    b/=gcd;
    if (b<0) b=-b;
    LL ans=x%b;
    if (ans<=0) ans+=b;
    return ans;
}

void Testcal()
{
	LL a,m;
	scanf("%lld%lld",&a,&m); //  ax mod m=1
	LL x=cal(a,m,1);
	cout<<x<<endl; 
}

 

4.欧拉定理

欧拉定理的应用

1、欧拉降幂公式,非常重要

用这个公式降幂之后再配合快速幂加速取模过程

2、求逆元

当(a,n)=1即底数和模数互素的时候才可

 

5.欧拉定理的特例——费马小定理

1、若p是一个素数,那么对于任意一个整数a, a^p-a都是p的倍数,即a^p≡a(mod p)

     感觉这条性质没啥用

2、若(a,p)=1,则  a^(p-1) ≡1(mod p) 

      当模数为素数而且底数和模数互素的时候才能用,用处:求逆元和降幂

 

6.求逆元的三个方法

ax=1(mod n)

1、扩展欧几里得,适用于一切情况

2、欧拉公式,适用于(a,n)=1

3、费马小定理,适用于(a,n)=1且n为素数

 

7.分解质因数(小数据)

int cnt[1000000];

void Divide(int N)
{
	int n=N, i=1, p=0;
	while (n!=0 && i<=tot)
	{
		p=0;
		while (n%prime[i]==0) p++, n /= prime[i];
		cnt[i]=p;
		i++;
	}
}

// 主函数中这样调用
Divide(2*3*5*7*11*13*13*13*19);   //  分解质因数 

 

8.中国剩余定理

问题

解法

LL ex_gcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    LL ans=ex_gcd(b,a%b,x,y);
    LL temp=x;
    x=y;
    y=temp-a/b*y;
    return ans;
}

LL China()
{
    LL M=m[1], A=a[1], t,d,x,y;
	int i;
    for(i=2; i<=n; i++) {
        d = ex_gcd(M,m[i],x,y);  //解方程
        if ((a[i]-A)%d!=0) return -1;  //无解
        x*=(a[i]-A)/d;  t=m[i]/d;  x=(x%t+t)%t;  //求x
        A=M*x+A;  M=M/d*m[i];  A%=M;  //模,防止爆
    }
    A=(A%M+M)%M;
    return A;
}

void TestChina()
{
	cin>>n;
	for (int i=1; i<=n; i++) cin>>m[i]>>a[i];  
	LL x=China();
	cout<<x<<endl; 
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值