数论总结(持续更新)

来源:互联网 发布:中国中元国际待遇 知乎 编辑:程序博客网 时间:2024/05/21 23:31

数论总结

欧拉定理

aφ(n)1(modn)

φ(n) 为欧拉函数

使用条件为gcd(a,n) = 1。

欧拉降幂公式:

abab%φ(n)+φ(n)(modn)(b>φ(n))

求欧拉函数:

//直接求phi  int get_phi(int c)  {      LL ans = c;      int m = sqrt(c+0.5);      for(int i = 2; i <= m; ++i)      {          if(c % i == 0)          {              ans = ans/i*(i-1);              while(c % i ==0)c/=i;          }      }      if(c > 1)ans = ans/c*(c-1);      return ans;  }  
//线性筛法,快的飞起  bool vis[MAXN];  int prime[MAXN];  int phi[MAXN];  int tot;  void init()  {      memset(vis, false, sizeof(vis));      phi[1] = 1;      tot = 0;      for(int i = 2; i < MAXN; i ++)      {          if(!vis[i])          {              prime[tot ++] = i;              phi[i] = i - 1;          }          for(int j = 0; j < tot; j ++)          {              if(i * prime[j] >= MAXN) break;              vis[i * prime[j]] = 1;              if(i % prime[j] == 0)              {                  phi[i * prime[j]] = phi[i] * prime[j];                  break;              }              else              {                  phi[i * prime[j]] = phi[i] * phi[prime[j]];              }          }      }  }  

素数筛:

void get_prim()  {      for(int i = 2; i < MAXN; ++i)      {          if(!vis[i])prim[tot++] = i;          for(int j = 0; j < tot; ++j)          {              if(prim[j]*i > MAXN)break;              vis[i*prim[j]] = 1;              if(i%prim[j] == 0)break;          }      }  }  

Miller_Rabin 算法进行素数测试 pollard_rho 算法进行质因数分解

//****************************************************************  // Miller_Rabin 算法进行素数测试  //速度快,而且可以判断 <2^63的数  //****************************************************************  const int S = 10;  //计算x*y%c  LL modular_multi(LL x,LL y,LL mo)  {      LL t;      x%=mo;      for(t=0;y;x=(x<<1)%mo,y>>=1)          if (y&1)              t=(t+x)%mo;      return t;  }  //计算num^t%c  LL modular_exp(LL num,LL t,LL mo)  {      LL ret=1,temp=num%mo;      for(;t;t>>=1,temp=modular_multi(temp,temp,mo))          if (t&1)              ret=modular_multi(ret,temp,mo);      return ret;  }  bool miller_rabbin(LL n)  {      if (n==2)return true;      if (n<2||!(n&1))return false;      int t=0;      LL a,x,y,u=n-1;      while((u&1)==0) t++,u>>=1;      for(int i=0;i<S;i++)      {          a=rand()%(n-1)+1;          x=modular_exp(a,u,n);          for(int j=0;j<t;j++)          {              y=modular_multi(x,x,n);              if (y==1&&x!=1&&x!=n-1)                  return false;              ///其中用到定理,如果对模n存在1的非平凡平方根,则n是合数。              ///如果一个数x满足方程x^2≡1 (mod n),但x不等于对模n来说1的两个‘平凡’平方根:1或-1,则x是对模n来说1的非平凡平方根              x=y;          }          if (x!=1)///根据费马小定理,若n是素数,有a^(n-1)≡1(mod n).因此n不可能是素数              return false;      }      return true;  }
//************************************************  //pollard_rho 算法进行质因数分解  //************************************************  long long factor[100];//质因数分解结果(刚返回时是无序的)  int tol;//质因数的个数。数组小标从0开始  long long gcd(long long a,long long b)  {      if(a==0)return 1;//???????      if(a<0) return gcd(-a,b);      while(b)      {          long long t=a%b;          a=b;          b=t;      }      return a;  }  long long Pollard_rho(long long x,long long c)  {      long long i=1,k=2;      long long x0=rand()%x;      long long y=x0;      while(1)      {          i++;          x0=(modular_multi(x0,x0,x)+c)%x;          long long d=gcd(y-x0,x);          if(d!=1&&d!=x) return d;          if(y==x0) return x;          if(i==k){y=x0;k+=k;}      }  }  //对n进行素因子分解  void findfac(long long n)  {      if(miller_rabbin(n))//素数      {          factor[tol++]=n;          return;      }      long long p=n;      while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);      findfac(p);      findfac(n/p);  } 

求1~n的素数的个数1e11

#define MAXN 100    // pre-calc max n for phi(m, n)  #define MAXM 10010 // pre-calc max m for phi(m, n)  #define MAXP 40000 // max primes counter  #define MAX 400010    // max prime  #define setbit(ar, i) (((ar[(i) >> 6]) |= (1 << (((i) >> 1) & 31))))  #define chkbit(ar, i) (((ar[(i) >> 6]) & (1 << (((i) >> 1) & 31))))  #define isprime(x) (( (x) && ((x)&1) && (!chkbit(ar, (x)))) || ((x) == 2))  long long n;  long long dp[MAXN][MAXM];  unsigned int ar[(MAX >> 6) + 5] = { 0 };  int len = 0, primes[MAXP], counter[MAX];  void Sieve() {      setbit(ar, 0), setbit(ar, 1);      for (int i = 3; (i * i) < MAX; i++, i++) {          if (!chkbit(ar, i)) {              int k = i << 1;              for (int j = (i * i); j < MAX; j += k) setbit(ar, j);          }      }      for (int i = 1; i < MAX; i++) {          counter[i] = counter[i - 1];          if (isprime(i)) primes[len++] = i, counter[i]++;      }  }  void init() {      Sieve();      for (int n = 0; n < MAXN; n++) {          for (int m = 0; m < MAXM; m++) {              if (!n) dp[n][m] = m;              else dp[n][m] = dp[n - 1][m] - dp[n - 1][m / primes[n - 1]];          }      }  }  long long phi(long long m, int n) {      if (n == 0) return m;      if (primes[n - 1] >= m) return 1;      if (m < MAXM && n < MAXN) return dp[n][m];      return phi(m, n - 1) - phi(m / primes[n - 1], n - 1);  }  long long Lehmer(long long m) {      if (m < MAX) return counter[m];      long long  res = 0;      int i, a, s, c,  y;      s = sqrt(0.9 + m), y = c = cbrt(0.9 + m);      a = counter[y], res = phi(m, a) + a - 1;      for (i = a; primes[i] <= s; i++) res = res - Lehmer(m / primes[i]) + Lehmer(primes[i]) - 1;      return res;  }  

计算二次剩余

/********************************* 计算二次剩余模版即x^2 = n(mod)p *********************************/  typedef long long ll;  ll tmod;  ll mod(ll n,ll p)  {      ll temp = 1;      while(p > 0)      {          if(p & 1) temp = temp * n % tmod;          n = n * n % tmod;          p >>= 1;      }      return temp;  }  ll pows(ll n)  {      ll i;      ll temp = 1;      for(i = 0; i < n; i++)          temp *= 2;      return temp;  }  int main()  {      int n,p,cs;      ll z,q,s,c;      ll r,t,m,b,i;      ll minx;      scanf("%d",&cs);      while(cs--)      {          scanf("%d%d",&n,&p);          //p=2时特判          if(p == 2)          {              if(n % p == 1)printf("1\n");              else printf("No root\n");              continue;          }          //如果无解          tmod = p;          if(mod(n,(p - 1) / 2) != 1)          {              printf("No root\n");              continue;          }          q = p - 1;          s = 0;          while(q % 2 == 0)          {              q /= 2;              s ++;          }          if(s == 1)          {              r = mod(n,(p + 1) / 4);          }          else          {              while(1)              {                  z = 1 + rand() % (p - 1);                  if(mod(z,(p - 1) / 2) == (p - 1)) break;              }              c = mod(z,q);              r = mod(n,(1 + q) / 2);              t = mod(n,q);              m = s;              while(1)              {                  if(t % p == 1) break;                  for(i = 1; i < m; i++)                  {                      if(mod(t,pows(i)) == 1) break;                  }                  b = mod(c, pows(m - i - 1));                  r = r * b % p;                  t = t * b * b % p;                  c = b * b % p;                  m = i;              }          }          r = (r % p + p) % p;          //如果只有一个          if(r == p - r)cout<<r<<endl;          //如果有两个按照升序输出          else          {              minx = min(r,p - r);              cout<<minx<<" "<<(p - minx)<<endl;          }      }      return 0;  }  

计算离散对数

/*************************************     *baby_step giant_step     *应用条件n必须为素数     *a^x = b (mod n) ,a,b < n     *求解上式 0<=x < n的解 *************************************/  const int MOD = 76543;  int hs[MOD],head[MOD],Next[MOD],id[MOD],top;  void Insert(int x,int y)  {      int k = x%MOD;      hs[top] = x, id[top] = y, Next[top] = head[k], head[k] = top++;  }  int Find(int x)  {      int k = x%MOD;      for(int i = head[k]; i != -1; i = Next[i])          if(hs[i] == x)              return id[i];      return -1;  }  int BSGS(int a,int b,int n)  {      memset(head,-1,sizeof(head));      top = 1;      if(b == 1)return 0;      int m = sqrt(n*1.0), j;      long long x = 1, p = 1;      for(int i = 0; i < m; ++i, p = p*a%n)Insert(p*b%n,i);      for(long long i = m; ;i += m)      {          if( (j = Find(x = x*p%n)) != -1 )return i-j;//找到了可行解          if(i > n)break;      }      //如果无解      return -1;  }  

原根

哪些数有原根?

n=124pr2pr期中p为奇素数,r为任意的正整数。

原根的一些性质:

•一个数n如果有原根,那么有φ(φ(n))

•高斯证明了:

•一个数n的全体原根乘积模n余1

•一个数n的全体原根总和模n余μ(n-1)(莫比乌斯函数)

求出n的所有原根,不存在原根输出-1

const int N = 1000000;    bool f[N];    int phi(int x){        if(f[x])    return x-1;        int ans = x;        for(int i=2; i<=x; i++){            if(x%i==0){                while(x%i==0)   x/=i;                ans = ans - ans/i;            }        }        if(x>1) ans = ans - ans/x;        return ans;    }    int gcd(int a, int b){        swap(a,b);        int c = a%b;        while(c){            a=b; b=c; c=a%b;        }        return b;    }    int quick_mod(int x, int p, int mod){        long long s = 1;        long long a = x;        while(p){            if(p&1) s = (s*a)%mod;            a = a*a%mod;            p>>=1;        }        return (int)s;    }    vector<int> V;    vector<int> G;    void cal(int x){        G.clear();        if(f[x])    return;        else{            for(int i=2; i*i<=x; i++){                if(x%i==0){                    G.push_back(i);                    if(i*i!=x)  G.push_back(x/i);                }            }        }    }    bool exist(int n){        if(n%2==0)  n/=2;        if(f[n])    return 1;        for(int i=3; i*i<=n; i+=2){            if(n%i==0){                while(n%i==0)   n/=i;                return n==1;            }        }        return 0;    }    void solve(int n){        if(n==2){            puts("1");            return;        }        if(n==4){            puts("3");            return;        }        if(!exist(n)){            puts("-1");            return;        }        int p = phi(n);        cal(p);        int x = -1;        for(int i=2; i<n; i++){            bool flag = 1;            if(quick_mod(i, p, n)!=1)   continue;            for(int j=0; j<G.size(); j++){                if(quick_mod(i, G[j], n)==1){                    flag = 0;                    break;                }            }            if(flag){                V.resize(1);                V[0] = x = i;                break;            }        }        if(x==-1){            puts("-1");            return;        }        for(int i=2; i<p; i++){            if(gcd(i, p)==1)    V.push_back(quick_mod(x, i, n));        }        sort(V.begin(), V.end());        vector<int>::iterator it=unique(V.begin(), V.end());        V.erase(it, V.end());        for(int i=0; i<V.size(); i++){            if(i)   putchar(' ');            printf("%d", V[i]);        }        puts("");    }    int main(){        memset(f, 1, sizeof(f));        f[0] = f[1] = 0;        for(int i=2; i<N; i++){            if(f[i]){                for(int j=i<<1; j<N; j+=i)  f[j]=0;            }        }        int n;        while(~scanf("%d", &n)) solve(n);        return 0;    }    

组合数学

n球m盒分配问题

球可分辨 盒子可分辨 盒可空 方案数 是 是 是 mn 是 是 否 m!S2(n,m) 是 否 是 mi=1S2(n,i) 是 否 否 S2(n,m) 否 是 是 Cm1n+m1 否 是 否 Cm1n1 否 否 是 分拆数(n+m,m) 否 否 否 分拆数(n,m)

第一类斯特林数:

把一个包含n个元素的集合分成k个环排列的方法数。

    s[1][1] = 1;    for(int i = 2; i <= 20; ++i)        for(int j = 1; j <= i; ++j)        {            s[i][j] = s[i-1][j-1] + s[i-1][j]*(i-1);        }

第二类斯特林数:

把一个包含n个元素的集合分成k个非空子集的方法数。

for(int i = 1; i <= 2000; ++i)    {        s[i][1] = 1;        for(int j = 2; j <= i; ++j)        {            s[i][j] = s[i-1][j-1] + j*s[i-1][j];        }    }

Lucas定理:

n,m比较大,p可能为和数。

LL quick_mod(LL a, LL b)    {        LL ans = 1;        a %= p;        while(b)        {            if(b & 1)            {                ans = ans * a % p;                b--;            }            b >>= 1;            a = a * a % p;        }        return ans;    }    LL C(LL n, LL m)    {        if(m > n) return 0;        LL ans = 1;        for(int i=1; i<=m; i++)        {            LL a = (n + i - m) % p;            LL b = i % p;            ans = ans * (a * quick_mod(b, p-2) % p) % p;        }        return ans;    }    LL Lucas(LL n, LL m)    {        if(m == 0) return 1;        return C(n % p, m % p) * Lucas(n / p, m / p) % p;    }   
原创粉丝点击