数论-知识

-----(1)欧拉函数:求不大于一个数的与其互质的数的个数

1.如果只用求一个数的话

int phi(int x){
    int res=x;
    for(int i = 2; i <= x ; i++){
        if(x%i == 0){
            res=res/p*(p-1);
            while(x%i == 0)
                x/=i;
        }
    }
    if(x>1) res=res/x*(x-1);
    return res;
}

2.如果想要表示所有的话

#include <iostream>

using namespace std;
const int N = 1e6+10;
int primes[N],cnt=0;
int euler[N];
bool st[N];
void get_euler(){

    euler[1]=1;
    for(int i = 2; i <= n ; i++){
        if(st[i]){
            primes[cnt++]=i;
            euler[i]=i-1;
        }
        for(int j = 0 ; primes[j]<=n/i; j++){
            int t=primes[j]*i;
            if(i%primes[j] == 0){
                euler[primes[j]*i]=primes[j]*euler[i];
                break;
            }
            else{
                euler[primes[j]*i]=euler[i]*(primes[j]-1);
            }
        }
    }
}

------(2).欧几里得算法

int gcd(int a, int b){
    
    if(!b) return a;
    return gcd(b,a%b);
}
int exgcd(int a,int b,int &x,int &y){///扩展欧几里得算法
    
    if(!b){
        x=1,b=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y -= a/b*x;
    return d;
}

在这里插入图片描述
---------4.线性同余方程

其与扩展欧几里得其实是同一个式子
在这里插入图片描述
所以只需要在用扩展欧几里得算法求出Xo,Yo之后都乘c/gcd(a,b)
!!!这里有一个大坑:
求出X后则真正的Xo应该是Xo*(c/gcd(a,b))不能写成Xo/gcd(a,b)*c
最好写成 c/gcd(a,b)*Xo

有一些细节需要注意:
1.需要判断是否有解
c%d!=0则无解
2.当gcd(a,b)==1时方程在[0,b-1] 有唯一的解,gcd(a,b)==d时在[0,b/d-1]有唯一的解,所以要求最小非负整数时,模的余数变一下

ll EXGCD(ll a,ll b,ll &x,ll &y){

    if(!b){
        x=1,y=0;
        return a;
    }
    ll d=EXGCD(b,a%b,y,x);
    y-=a/b*x;
    return d;

}
int main()
{
	d=EXGCD(a,b,X,Y),r=b/d;
	X=(X*(x-y)/d%r+r)%r;
}

-------5中国剩余定理(Chinese Remainder Theorem, CRT)
zyzyyds.
OI Wiki.
1.m1,m2,m3互为质数
void EXGCD(ll a, ll b, ll &x, ll &y){
    
    if(b == 0){
        x=1,y=0;return;
    }
    exgcd(b,a%b,y,x);
   y-=a/b*x;

}
int main()
{
    while(cin >> n){
        ll m=1,ans=0;
        for(int i = 1 ; i <= n ; i++){
            cin >> m[i] >> a[i];
            M*=m[i];
        }
        for(int i =1 ; i <= n ; i++){
            ll Mi=M/m[i];
            ll x,y;
            EXGCD(Mi,m[i],x,y);
            ans=(ans+a[i]*Mi*x)%MOD;
        }
        return (ans+MOD)%MOD;
    }
    return 0;
}

2.一般情况

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
const int N =1e5+10;
typedef long long ll;
ll m[N],r[N];
int n;
ll EXGCD(ll a, ll b, ll &x, ll &y){

    if(!b){
        x=1,y=0;
        return a;
    }
    ll d=EXGCD(b,a%b,y,x);
    y -= a/b*x;
    return d;
}
ll solve(){

    ll M=m[1],R=r[1],x,y,d;
    for(int i = 2 ; i <= n ; i++){
        d=EXGCD(M,m[i],x,y);
        if((r[i]-R)%d) return -1;
        x=(r[i]-R)/d*x%(m[i]/d);
        R+=M*x;
        M=M/d*m[i];
        R=R%M;
    }
    return R > 0? R: R+M;

}
int main()
{
    while(scanf("%d",&n)!=EOF){
        for(int i = 1 ; i <= n ; i++){
            scanf("%lld %lld",&m[i],&r[i]);
        }
        printf("%lld\n",solve());
    }
    return 0;
}

------6求素数个数
埃氏筛 O (nlogn)

int primes[N],cnt=0;
bool st[N];
void get_primes(int n){
    
    st[0]=st[1]=1;
    for(int i = 2; i <= n ; i++){
    	if(st[i]) continue;
        primes[cnt++]=i;
        for(int j = 2*i; j <= n ; j+=i){
            st[j]=true;
        }
    }
}

线性筛(欧拉筛)O (n)

int primes[N],cnt=0;
bool st[N];
void get_primes(int n){

    for(int i = 2 ; i <= n ; i++){
        if(!st[i]) primes[cnt++]=i;
        for(int j = 0 ; primes[j]<=n/i && j < cnt ; j++){
            st[primes[j]*i]=true;
            if(i%primes[j] == 0)break;
        }
    }
}

-----7组合数

在这里插入图片描述
在这里插入图片描述
2.线性递推阶乘逆元求组合数
!!! 注意可以的条件是: MOD>max(n,m)
不然就每一个要找的数都求一下逆元

ll inv[N],fac[N];
ll ksm(ll a, ll b){
    
    ll res=1;
    a=a%MOD;
    while(b){
        if(b&1) res=res*a%MOD;
        a=a*a%MOD;
        b >>= 1;
    }
    return res;
}
void init(){
    
    fac[0]=1;
    for(int i = 1 ; i <= N ; i++) fac[i]=fac[i-1]*i%MOD;
    inv[N-1]=ksm(fac[N-1],MOD-2);
    for(int i=N-2; i>= 0 ; i--) inv[i]=inv[i+1]*(i+1);
}
ll c(ll n,ll m){
    
    if(m>n) return 0;
    return fac[n]*inv[n-m]%MOD*inv[m]%MOD;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值