Thematic001.数论专题

目录

  • 素数
  • 欧拉函数
  • 约数
  • 乘法逆元
  • 欧几里得(拓展)
  • 中国剩余定理
  • 中国剩余定理(拓展)
  • BSGS
  • BSGS(拓展)

素数

例题

暴力 (\(O(n\sqrt{n})\)

bool Prime[MAXN];

void Check(int n)
  {
    for (int i=1;i<=n;i++)
      {
        if (i<2) continue;
        if (i==2||i==3)
          {
            Prime[i]=true;
            continue;
          }
        for (int j=2;j<=ceil(sqrt(i));j++) if (i%j==0)
          {
            Prime[i]=true;
            break;
          }
        Prime[i]=!Prime[i];
      }
  }

埃式筛法 (\(O(n\log n)\)

bool vis[MAXN];
int size,prime[MAXN];

void FindPrime(int n)
  {
    vis[0]=vis[1]=true;
    for (int i=2;i<=n;i++) if (!vis[i])
      {
        prime[++size]=i;
        for (int j=2;i*j<=n;j++) vis[i*j]=true;
      }
  }

欧拉筛法 (\(O(n)\)

bool vis[MAXN];
int size,prime[MAXN];

void FindPrime(int n)
  {
    vis[0]=vis[1]=true;
    for (int i=2;i<=n;i++)
      {
        if (!vis[i]) prime[++size]=i;
        for (int j=1;j<=size&&i*prime[j]<=n;j++)
          {
            vis[i*prime[j]]=true;
            if (i%prime[j]==0) break;
          }
      }
  }

欧拉函数

直接求 \(\phi\) (\(n\)) (\(O(\sqrt{n})\)

int FindPhi(int n)
  {
    int ans=n;
    for (int i=2;i*i<=n;i++)
      {
        if (n%i==0)
          {
            ans-=ans/i;
            while (n%i==0) n/=i;
          }
      }
    if (n>1) ans-=ans/n;
    return ans;
  }

同时求 \(\phi\) (\(1\)) 到 \(\phi\) (\(n\))时与 \(1\)\(n\) 的素数 (\(O(n)\)

bool vis[MAXN];
int size,Prime[MAXN],Phi[MAXN];

void Find_Phi_and_Prime(int n)  
  {  
    for (int i=2;i<n;i++)  
      {  
        if (!vis[i])  
          {  
            Prime[++size]=i;  
            Phi[i]=i-1;  
          }  
        for (int j=1;j<=size&&i*Prime[j]<n;j++)  
          {  
            vis[i*Prime[j]]=true;  
            if (i%Prime[j]==0)  
              {  
                Phi[i*Prime[j]]=Phi[i]*Prime[j];  
                break;  
              }  
            else Phi[i*Prime[j]]=Phi[i]*(Prime[j]-1);
          }  
      }  
  } 

约数

例题

辗转相除法

int GCD(int a,int b)
  {
    if (b==0) return a;
    return GCD(b,a%b);
  }

二进制算法

  • 低精

int GCD(int x,int y)
  {
    int i,j;
    if (x==0) return y;
    if (y==0) return x;
    for (i=0;(x&1)==0;i++) x>>=1;
    for (j=0;(y&1)==0;j++) y>>=1;
    if (j<i) i=j;
    while (1)
      {
        if (x<y) x^=y,y^=x,x^=y;
        if ((x-=y)==0) return y<<i;
        while ((x&1)==0) x>>=1;
      }
  }
  • 高精

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

struct Data
  {
    int a[2005];
    int num;
  };
char c[10005];

void div2(Data &x)
  {
    if (x.a[x.num]==1)
      {
        x.a[x.num-1]+=10000000;
        x.num--;
      }
    for (int i=x.num;i>=1;i--)
      {
        if (x.a[i]&1) x.a[i-1]+=10000000;
        x.a[i]>>=1;
      }
  }

void plus2(Data &x)
  {
    for (int i=1;i<=x.num;i++) x.a[i]<<=1;
    for (int i=1;i<x.num;i++)
      {
        if (x.a[i]>=10000000)
          {
            x.a[i]-=10000000;
            x.a[i+1]++;
          }
      }
    if (x.a[x.num]>=10000000)
      {
        x.a[x.num]-=10000000;
        x.a[x.num+1]=1;
        x.num++;
      }
  }

void sub(Data &x,Data y)
  {
    for (int i=1;i<=y.num;i++) x.a[i]-=y.a[i];
    for (int i=1;i<x.num;i++)
      {
        if (x.a[i]<0)
          {
            x.a[i+1]--;
            x.a[i]+=10000000;
          }
      }
    if (x.a[x.num]==0) x.num--;
  }

bool comp(Data &x,Data &y)
  {
    if (x.num>y.num) return false;
    if (x.num<y.num)
      {
        swap(x.num,y.num);
        for (int i=1;i<=max(x.num,y.num);i++) swap(x.a[i],y.a[i]);
        return false;
      }
    for (int i=x.num;i>=1;i--)
      {
        if (x.a[i]>y.a[i]) return false;
        if (x.a[i]<y.a[i])
          {
            swap(x.num,y.num);
            for (int i=1;i<=max(x.num,y.num);i++) swap(x.a[i],y.a[i]);
            return false;
          }
      }
    return true;
  }

int main()
  {
    Data n,m;
    int stop,x,y,t,cnt;
    scanf("%s",c);
    for (int i=strlen(c)-1;i>=0;i-=7)
      {
        n.num++;
        n.a[n.num]=0;
        stop=max(i-6,0);
        for (int j=i;j>=stop;j--) n.a[n.num]+=(c[j]-'0')*pow(10,i-j);
      }
    scanf("%s",c);
    for (int i=strlen(c)-1;i>=0;i-=7)
      {
        m.num++;
        m.a[m.num]=0;
        stop=max(i-6,0);
        for (int j=i;j>=stop;j--) m.a[m.num]+=(c[j]-'0')*pow(10,i-j);
      }
    for (x=0;!(n.a[1]&1);x++) div2(n);
    for (y=0;!(m.a[1]&1);y++) div2(m);
    if (y<x) x=y;
    while (1)
      {
        if (comp(n,m)) 
          {
            while(x--) plus2(n);
            printf("%d",n.a[n.num]);
            for (int i=n.num-1;i>=1;i--)
              {
                t=n.a[i];
                cnt=0;
                while (t/10) t/=10,cnt++;
                for (int i=1;i<7-cnt;i++) printf("0");
                printf("%d",n.a[i]);
              }
            return 0;
          }
        sub(n,m);
        while (!(n.a[1]&1)) div2(n);
      }
    return 0;
  }

乘法逆元

例题

代码

  • 欧几里得(拓展)

long long exgcd(long long a,long long b,long long &x,long long &y)
  {
    if (b==0)
      {
        x=1,y=0;
        return a;
      }
    long long r=exgcd(b,a%b,x,y);
    long long t=x;
    x=y;
    y=t-(a/b)*y;
    return r;
  }
  • 快速幂

long long fastpow(long long a,long long b,long long p) //a^b%p
  {
    if (b==0) return 1;
    if (b==1) return a%p;
    long long half=fastpow(a,b/2,p);
    if (b&1) return ((half%p*half%p)%p*a)%p;
    return (half%p*half%p)%p;
  }
  
int main()
  {
    //...
    long long x=fastpow(a,b-2,b);
    //...
  }
  • 线性算法求 \(1\)\(n\)\(b\) 的逆元 (\(O(n)\)

inv[1]=1;
for (int i=2;i<=n;i++)
    inv[i]=(p-p/i)*inv[p%i]%p;

欧几里得(拓展)

代码

long long exGCD(long long a,long long b,long long &x,long long &y)
  {
    if (b==0)
      {
        x=1,y=0;
        return a;
      }
    long long r=exGCD(b,a%b,x,y);
    long long t=x;
    x=y;
    y=t-(a/b)*y;
    return r;
  }

中国剩余定理

例题

代码

long long CRT(void)
  {
    long long M=1,ans=0;
    for (int i=1;i<=n;i++) M*=m[i];
    for (int i=1;i<=n;i++)
      {
        long long tM=M/m[i];
        long long x,y;
        exgcd(tM,m[i],x,y);
        ans=(ans+tM*x*a[i])%M;
      }
    return (ans+M)%M;
  }

中国剩余定理(拓展)

例题

代码

long long exCRT(void)
  {
    long long M=m[1],ans=b[1],x,y,g,t,k1;
    for (int i=2;i<=n;i++)
      {
        g=exgcd(M,m[i],x,y);
        if ((b[i]-ans)%g) return -1;
        k1=x*(b[i]-ans)/g;
        t=m[i]/g;
        x=(k1%t+t)%t;
        ans=M*x+ans;
        M=M/g*m[i];
      }
    return (ans%M+M)%M;
  }

BSGS

例题

代码

long long BSGS(long long a,long long b,long long p)
  {
    a%=p,b%=p;
    if (a==0)
      {
        if (b==0) return 0;
        return -1;
      }
    map <long long,long long> M;
    M.clear();
    long long temp=b,m=ceil(sqrt(p));
    for (int i=0;i<=m;i++,temp=temp*a%p) M[temp]=i;
    temp=a=fastpow(a,m,p);
    for (int i=1;i<=m;i++,temp=temp*a%p) if (M.count(temp)) return i*m-M[temp];
    return -1;
  }

BSGS(拓展)

例题

代码

long long inv(long long a,long long p)
  {
    long long x,y,ans;
    exgcd(a,p,x,y);
    return (x%p+p)%p;
  }

long long exBSGS(long long a,long long b,long long p)
  {
    if (b==1||p==1) return 0;
    long long x,y,g,k=0,na=1;
    while (g=exgcd(a,p,x,y))
      {
        if (g==1) break;
        if (b%g) return -1;
        k++;
        b/=g;
        p/=g;
        na=na*(a/g)%p;
        if (na==b) return k;
      }
    long long ans=BSGS(a,b*inv(na,p)%p,p);
    if (ans==-1) return -1;
    return ans+k;
  }
posted @ 2020-01-18 19:58  666DHG  阅读(251)  评论(0编辑  收藏  举报