数论初步

约数相关

  1. 带余除法和整数
  • 对于整数a,b,存在唯一的两个整数q,r使得\(b=aq+r(0<=r<=|a|)\)
  • 同时可以得到\(b=\lfloor \frac{b}{a} \rfloor * a + b \mod a\)
  • 当r=0时,我们称a整除b,记作\(a|b\)
  • 此时也称b为a的倍数,a为b的约数
  1. 整除的性质
  • \(a|c,b|c,(a,b)=1 \to ab|c\)
  • \(a|bc,(a,b)=1 \to a|c\)
  • \(p|ab \to p|a或p|b\)
  1. 素数与合数
  • 若大于1的正整数P约数只有1和p本身,则称其为素数(质数)
  • 若其有超过两个约数,则称其为合数
  • 特别的,1不是质数
  • 若两个数A,B最大公约数为1,则称A,B互质
  1. 算数基本定理
  • 任何一个自然是N,可以唯一分解成有限个质数的乘积(在康托展开也有提到),式子表达为:\(N=\pi _ {i=1} ^ {m} p_i ^{k_i}\)
  • 其中\(p_1<p_2<p_3<…<p_n\)
  • 这样的分解称为N的标准分解式

小测验 #1

  • 给定一个不超过\(10^{14}\)的正整数,如何计算其全部约数
long long a[N];
int cnt;
inline void ys(long long x){
    int sx=sqrt(x);
    if(x/sqrt(x)==sx)a[++cnt]=sqrt(x);//防止完全平方数出现两次
    for(int i=1;i<sx;i++){
        if(!(x%i)){
            a[++cnt]=i;
            a[++cnt]=x/i;
        }
    }
}
  • 给定一个不超过\(10^{14}\)的正整数,如何计算其标准分解?
const int N=1e7+5;
int a[N],cnt;
inline void bzfj(long long x){
    for(long long i=2;i*i<=x;i++){
        if(!(x%i)){
            a[++cnt]=i;
            while(!(x%i))
                x/=i;
        }
    }
    if(x!=1){
        a[++cnt]=x;
    }
}

注:以上两篇代码都没有运行过,出锅了找我。

  1. 素数无限定理
  • 正整数集中包含无限个素数

一些常用的复杂度常识

  • 素数分布:\(lim_{n \to \infty} \frac {\pi (n) * ln n} {n}=1\)
  • 调和级数:\(\sum _{1<=i<=n} \frac {N} {i}=O(N log n)\)
//调和级数循环举例
for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	……
  • 素数调和级数\(\sum {1<=p<=n} \frac {1} {i} =O(log^2n)\)
  1. 约数与倍数
  • 对于a,b,如果\(d|a,d|b\),称d是a,b的公约数
  • 对于其中最大的d,称d是a,b的最大公约数,记为\(d=(a,b)\)
  • 对于a,b,如果\(a|d,b|d\),称d是a,b的公倍数
  • 对于其中最小的d,称d是a,b的最小公倍数,记为\(d=[a,b]\)
  1. 集合含义
  • GCD和LCM本质上是在研究两数的质因数分解的指数关系
  • 两个很大的数,以标准分解形式给出,求其GCD?
  • 两个很大的数,以标准分解形式给出,求其LCM?
  • \(A=p_1^{a_1}*p_2^{a_2}*…*p_n^{a_n},B=p_1^{a_1}*p_2^{a_2}*…*p_n^{a_n}\)
  • 因为太简单了不会写,所以直接口胡
  • \(GCD=\pi _ {i=1}^{n}p_i^{min(a_i,b_i)}\)
  • \(LCM=\pi _ {i=1}^{n}p_i^{mix(a_i,b_i)}\)
  1. 欧几里得算法
  • 算最大公约数
  • \((a,b)=(a-b,b)=(a \mod b,b)\)
  • 复杂度分析(分类讨论a<b与a>b,每次一定/2所以复杂度为\(log n\)
  1. 裴蜀定理

裴蜀定理(或贝祖定理)得名于法国数学家艾蒂安·裴蜀,说明了对任何整数a、b和它们的最大公约数d,关于未知数x和y的线性不定方程(称为裴蜀等式):若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。 --百度百科

  • \(\forall a,b,d,(a,b)|d等价于\exists u,v \in N,ua+vb=d\)
  • 判断二元一次方程无解
  • 【例题1】【模板】裴蜀定理
inline int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
int n,ans=0;
int main(){
    read(n);
    for(int i=1,x;i<=n;i++){
        read(x);
        if(x<0)x=-x;
        ans=gcd(ans,x);
    }
    printf("%d",ans);
    return 0;
}

【例题2】瓶子和燃料

int n,k,ans=0;
//从n个数里选出k个数,求这k个数最大的gcd
map<int,int>mp;//数据太大,防止RE
int main(){
    read(n);read(k);
    for(int i=1,x;i<=n;i++){
        read(x);
        for(int j=1;j*j<=x;j++){
            if(x%j)continue;
            mp[j]++;
            int y=x/j;
            if(j!=y)mp[y]++;
            if(mp[y]>=k)ans=max(ans,y);
            if(mp[j]>=k)ans=max(ans,j);
        }
    }
    printf("%d",ans);
    return 0;
}
  1. 扩展欧几里得算法
/*void exgcd(int a,int b,int &x,int &y){
    if(b==0){x=1,y=0;return ;}
    exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-(a/b)*y;
}*/
void exgcd(int a,int b,int &x,int &y){
    if(b==0){x=1,y=0;return ;}
    exgcd(b,a%b,y,x);
    y-=(a/b)*x;
}
  1. 同余
  • \(a=b(\mod p)\),则存在整数k使得\(a=b+kp\)
  • \(a=b(\mod p)<=>p|b-a\)
  • \(a=b(\mod p),a=b(\mod q)<=>a=b(\mod [p,q])\)
  • \((k,p)=d,ka=kb(mod p)<=>a=b(\mod \frac {p} {d})\)
    ->同余方程\(x=a_1(\mod m_1);x=a_2(\mod m_2)\)
  • 何时有解?\(gcd(m_1,m_2)|(a_1-a_2)\)
  • 通解如何表示?设其中一个特解为x0则\(x=x_0+k*lcm(m_1,m_2)\)为通解
  • 最小正整数解\(x=(x%b+b)%b\)

【例题1】青蛙的约会

【例题2】荒岛猎人

12.快速幂与快速乘(不应该是龟速乘吗(雾)

//普通快速幂
inline int qpow(int a,int b,int mod){
    int res=1;
    while(b){
        if(b&1)res=a*res%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
struct Matrix{
    int a[N][N];
    Matirx(){
        memset(a,0,sizeof a);
    }
    inline void build(){
        for(int i=1;i<=n;i++)
            a[i][i]=1;
    }
}a,ans;
Matrix operator * (const Matrix &x,const Matrix &y){
    Matrix res;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                res.a[i][j]=res.a[i][j]+x.a[i][k]*y%mod;
            }
        }
    }
    return res;
}
signed main(){
    read(n);read(k);
    for(int i=1;i<=n;i++){
        for(int j=1;j<-n;j++){
            read(a.a[i][j]);
        }
    }
    ans.build();
    while(k){
        if(k&1)ans=ans*a;
        a=a*a;
        k>>=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            printf("%d",ans.a[i][j]);
        }
        puts("");
    }
}
posted @ 2021-07-08 18:01  无琛  阅读(89)  评论(0)    收藏  举报