zoukankan      html  css  js  c++  java
  • 数论模板

    数论:

    快速乘:

    ll ModMul(ll a,ll b,ll n){//快速积取模 a*b%n
        ll ans=0;
        while(b){
            if(b&1)
            ans=(ans+a)%n;
            a=(a+a)%n;
            b>>=1;
        }
        return ans;
    }

    快速幂:

    ll ModExp(ll a,ll b,ll n){  //快速幂取模 a^b%n
        ll ans=1;
        while(b){
            if(b&1)
            ans=ModMul(ans,a,n);
            a=ModMul(a,a,n);
            b>>=1;
        }
        return ans;
    }

    Miller-Rabin素数检测算法:

    bool miller_rabin(ll n){
        ll i,j,a,x,y,t,u,s=10;
        if(n==2)
            return true;
        if(n<2||!(n&1))
            return false;
        for(t=0,u=n-1;!(u&1);t++,u>>=1); //n-1=u*2^t
        for(i=0;i<s;i++){
            a=rand()%(n-1)+1;
            x=ModExp(a,u,n);
            for(j=0;j<t;j++){
                y=ModMul(x,x,n);
                if(y==1&&x!=1&&x!=n-1)
                    return false;
                x=y;
            }
            if(x!=1)
                return false;
        }
        return true;
    }

    素数筛(线性筛):

    const ll maxn=100000001;
    ll prime[maxn];      //就是个素数表
    bool sf[maxn];        //判断这个数是不是素数,sf[i]中的i是从1到maxn的数
    void sushu()
    {         //核心 欧拉筛代码
        ll num=0;        //num 用来记筛到第几个质数
        memset(sf,true,sizeof(sf));
        sf[1] = false;
        sf[0] = false;  //1 0 特判 
        for(int i = 2;i <= maxn; i ++)
        {          //外层枚举1~maxn
            if(sf[i]) prime[++num] = i;      //如果是质数就加入素数表
            for(int j = 1;j <= num;j ++)
            {       //内层枚举num以内的质数
                if(i * prime[j] > maxn) break; //筛完结束
                sf[i * prime[j]] = false;      //筛掉...
                if(i % prime[j] == 0) break;   //避免重复筛
            }
        } 
    }
    View Code

     求前n个素数和与个数 O(n^(3/4)):

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    
    ll check(ll v, ll n, ll ndr, ll nv) {
        return v >= ndr ? (n / v - 1) : (nv - v);
    }
    
    // ll S[10000000];
    // ll V[10000000];
    ll primenum(ll n) // O(n^(3/4))
    {
      ll r = (ll)sqrt(n);
      ll ndr = n / r;
      assert(r*r <= n && (r+1)*(r+1) > n);
      ll nv = r + ndr - 1;
      std::vector<ll> S(nv+1);
      std::vector<ll> V(nv+1);
      for(ll i=0;i<r;i++) {
        V[i] = n / (i+1);
      }
      for(ll i=r;i<nv;i++) {
        V[i] = V[i-1] - 1;
      }
      for(ll i = 0;i<nv;i++) {
        S[i] = V[i] - 1; //求素数个数
      }
      for(ll p=2;p<=r;p++) {
        if(S[nv-p] > S[nv-p+1]) {
          ll sp = S[nv-p+1]; // sum of primes smaller than p
          ll p2 = p*p;
      //    std::cout << "p=" << p << '
    '; // p is prime 
          for(ll i=0;i<nv;i++) {
            if(V[i] >= p2) {
              S[i] -= 1LL  * (S[check(V[i] / p, n, ndr, nv)] - sp);// //求素数个数
            }
            else break;
          }
        }
      }
      return S[0];
    }
    ll primesum(ll n) // O(n^(3/4))
    {
      ll r = (ll)sqrt(n);
      ll ndr = n / r;
      assert(r*r <= n && (r+1)*(r+1) > n);
      ll nv = r + ndr - 1;
      std::vector<ll> S(nv+1);
      std::vector<ll> V(nv+1);
      for(ll i=0;i<r;i++) {
        V[i] = n / (i+1);
      }
      for(ll i=r;i<nv;i++) {
        V[i] = V[i-1] - 1;
      }
      for(ll i = 0;i<nv;i++) {
        S[i] = V[i] * ( V[i] + 1) / 2 - 1; //求素数和
      }
      for(ll p=2;p<=r;p++) { // p is prime 
        if(S[nv-p] > S[nv-p+1]) {
          ll sp = S[nv-p+1]; // sum of primes smaller than p
          ll p2 = p*p; 
          for(ll i=0;i<nv;i++) {
            if(V[i] >= p2) {
            S[i] -= p* (S[check(V[i] / p, n, ndr, nv)] - sp); //求素数和
            }
            else break;
          }
        }
      }
      return S[0];
    }
    int main(int argc, char const *argv[]) {
    //  std::cout << primesum(1e6) << '
    ';
      std::cout << primenum(1e10) << '
    ';
      std::cout << primesum(2e6) << '
    ';
      cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.
    ";
      return 0;
    }
    View Code

     矩阵快速幂(嫖的):

    struct Mat
    {
        LL m[101][101];
    };//存储结构体
    Mat a,e; //a是输入的矩阵,e是输出的矩阵
    Mat Mul(Mat x,Mat y)
    {
        Mat c;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                c.m[i][j] = 0;
            }
        }
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                for(int k=1;k<=n;++k){
                    c.m[i][j] = c.m[i][j]%mod + x.m[i][k]*y.m[k][j]%mod;
                }
            }
        }
        return c;
    }
    Mat pow(Mat x,LL y)//矩阵快速幂
    {
        Mat ans = e;
        while(y){
            if(y&1) ans = Mul(ans,x);
            x = Mul(x,x);
            y>>=1;
        }
        return ans;
    }
    View Code

    这里顺便再来几个常见的矩阵递推式:

    1.f(n)=a*f(n-1)+b*f(n-2)+c;(a,b,c是常数)

    2.f(n)=c^n-f(n-1) ;(c是常数)

    3.f(n) = f(n-1)+f(n-2)

    ,

    欧拉函数 求 一个数的因子有多少个(大数 10^18级)

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <cstdlib>
    #include <iomanip>
    #include <cmath>
    #include <cassert>
    #include <ctime>
    #include <map>
    #include <set>
    using namespace std;
    #pragma comment(linker, "/stck:1024000000,1024000000")
    #define lowbit(x) (x&(-x))
    #define max(x,y) (x>=y?x:y)
    #define min(x,y) (x<=y?x:y)
    #define MAX 100000000000000000
    #define MOD 1000000007
    #define pi acos(-1.0)
    #define ei exp(1)
    #define PI 3.1415926535897932384626433832
    #define ios() ios::sync_with_stdio(true)
    #define INF 0x3f3f3f3f
    #define mem(a) (memset(a,0,sizeof(a)))
    typedef long long ll;
    const int s=8;
    char ch[26];
    ll mult_mod(ll a,ll b,ll c)
    {
        a%=c;
        b%=c;
        ll ret=0;
        ll tmp=a;
        while(b)
        {
            if(b&1){
                ret+=tmp;
                if(ret>c) ret-=c;
            }
            tmp<<=1;
            if(tmp>c) tmp-=c;
            b>>=1;
        }
        return ret;
    }
    ll pow_mod(ll a,ll n,ll mod)
    {
        ll ans=1;
        ll tmp=a%mod;
        while(n)
        {
            if(n&1) ans=mult_mod(ans,tmp,mod);
            tmp=mult_mod(tmp,tmp,mod);
            n>>=1;
        }
        return ans;
    }
    bool check(ll a,ll n,ll x,ll t)
    {
        ll ret=pow_mod(a,x,n);
        ll last=ret;
        for(int i=1;i<=t;i++)
        {
            ret=mult_mod(ret,ret,n);
            if(ret==1 && last!=1 && last!=n-1) return true;
            last=ret;
        }
        if(ret!=1) return true;
        else return false;
    }
    bool miller_pabin(ll n)
    {
        if(n<2) return false;
        if(n==2) return true;
        if((n&1)==0) return false;
        ll x=n-1;
        ll t=0;
        while((x&1)==0) {x>>=1;t++;}
        srand(time(NULL));
        for(int i=0;i<s;i++){
            ll a=rand()%(n-1)+1;
            if(check(a,n,x,t)) return false;
        }
        return true;
    }
    ll factor[110];
    int tol=0;
    ll gcd(ll a,ll b)
    {
        ll t;
        while(b)
        {
            t=a;
            a=b;
            b=t%b;
        }
        if(a>=0) return a;
        else return -a;
    }
    ll pollard_rho(ll x,ll c)
    {
        ll i=1,k=2;
        srand(time(NULL));
        ll x0=rand()%(x-1)+1;
        ll y=x0;
        while(1)
        {
            i++;
            x0=(mult_mod(x0,x0,x)+c)%x;
            ll d=gcd(y-x0,x);
            if(d!=1 && d!=x) return d;
            if(y==x0) return x;
            if(i==k){y=x0;k+=k;}
        }
    }
    void findfac(ll n,ll k)
    {
        if(n==1) return ;
        if(miller_pabin(n))
        {
            factor[tol++]=n;
            return ;
        }
        ll p=n;
        ll c=k;
        while(p>=n) p=pollard_rho(p,c--);
        findfac(p,k);
        findfac(n/p,k);
    }
    int main()
    {
        ll n;
        scanf("%lld",&n);
        if(miller_pabin(n)) printf("2
    ");
        else
        {
            findfac(n,107);
            ll ans=1;
            for(int i=0;i<tol;i++)
            {
                //printf("%lld ",factor[i]);
                ll pos=0;
                while(n>0 && (n%factor[i]==0))
                {
                    pos++;
                    n/=factor[i];
                }
    //            printf("%lld %lld
    ",factor[i],pos);
                if(pos) ans*=(pos+1);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    大数模板

    //首先大数加法 两个大数相加
    string sum(string s1,string s2)
    {
        if(s1.length()<s2.length())
        {
            string temp=s1;
            s1=s2;
            s2=temp;
        }
        int i,j;
        for(i=s1.length()-1,j=s2.length()-1;i>=0;i--,j--)
        {
            s1[i]=char(s1[i]+(j>=0?s2[j]-'0':0));   //注意细节
            if(s1[i]-'0'>=10)
            {
                s1[i]=char((s1[i]-'0')%10+'0');
                if(i) s1[i-1]++;
                else s1='1'+s1;
            }
        }
        return s1;
    }
    
    //然后大数乘以整形数
    
    string Multiply(string s,int x)  //大数乘以整形数
    {
        reverse(s.begin(),s.end());
        int cmp=0;
        for(int i=0;i<s.size();i++)
        {
            cmp=(s[i]-'0')*x+cmp;
            s[i]=(cmp%10+'0');
            cmp/=10;
        }
        while(cmp)
        {
            s+=(cmp%10+'0');
            cmp/=10;
        }
        reverse(s.begin(),s.end());
        return s;
    }
    
    //大数除以整形数
    
    
    string Except(string s,int x)  //大数除以整形数
    {
        int cmp=0,ok=0;
        string ans="";
        for(int i=0;i<s.size();i++)
        {
            cmp=(cmp*10+s[i]-'0');
            if(cmp>=x)
            {
                ok=1;
                ans+=(cmp/x+'0');
                cmp%=x;
            }
            else{
                if(ok==1)
                    ans+='0';  //注意这里啊。才找出错误
            }
        }
        return ans;
    }
    
    //思想就是模拟乘法运算,用大数乘以另一个数的每一位然后大数相加就是ans
    
    string sum(string s1,string s2)  //大数加法
    {
        if(s1.length()<s2.length())
        {
            string temp=s1;
            s1=s2;
            s2=temp;
        }
        int i,j;
        for(i=s1.length()-1,j=s2.length()-1;i>=0;i--,j--)
        {
            s1[i]=char(s1[i]+(j>=0?s2[j]-'0':0));   //注意细节
            if(s1[i]-'0'>=10)
            {
                s1[i]=char((s1[i]-'0')%10+'0');
                if(i) s1[i-1]++;
                else s1='1'+s1;
            }
        }
        return s1;
    }
     
    string Mult(string s,int x)  //大数乘以整形数
    {
        reverse(s.begin(),s.end());
        int cmp=0;
        for(int i=0;i<s.size();i++)
        {
            cmp=(s[i]-'0')*x+cmp;
            s[i]=(cmp%10+'0');
            cmp/=10;
        }
        while(cmp)
        {
            s+=(cmp%10+'0');
            cmp/=10;
        }
        reverse(s.begin(),s.end());
        return s;
    }
    string Multfa(string x,string y)  //大数乘法
    {
        string ans;
        for(int i=y.size()-1,j=0;i>=0;i--,j++)
        {
            string tmp=Mult(x,y[i]-'0');
            for(int k=0;k<j;k++)
                tmp+='0';
            ans=sum(ans,tmp);
        }
        return ans;
    }
    
    //
    string Multiply(string s,long x)  //大数乘以整形数
    {
        reverse(s.begin(),s.end());
        long cmp=0;
        for(int i=0; i<s.size(); i++)
        {
            cmp=(s[i]-'0')*x+cmp;
            s[i]=(cmp%10+'0');
            cmp/=10;
        }
        while(cmp)
        {
            s+=(cmp%10+'0');
            cmp/=10;
        }
        reverse(s.begin(),s.end());
        return s;
    }
    string Remove_later(string s)   //删除一个字符串的后倒0
    {
        int ok=1;
        for(int i=s.size()-1; i>=0; i--)
        {
            if(s[i]=='0'){
                s.erase(i);
            }
            else if(s[i]=='.')
            {
                s.erase(i);
                ok=0;
            }
            else
                ok=0;
            if(ok==0)
                break;
        }
        return s;
    }
    string factorial(string s,int n)   //浮点数的n次方
    {
        if(n==0)
            return "1";
        string cmp="",count="";
        long x=0,point=0;
        for(int i=0; i<s.size(); i++)
            if(s[i]!='.')
            {
                cmp+=s[i];
                x=x*10+(s[i]-'0');
            }
            else
                point=s.size()-1-i;
        for(int i=1; i<n; i++)
        {
            cmp=Multiply(cmp,x);
        }
        int ans_point=cmp.size()-n*point;
        if(ans_point<0)
        {
            count+='.';
            for(int i=ans_point; i!=0; i++)
                count+='0';
        }
        string::iterator it=cmp.begin();
        if(ans_point>=0&&ans_point<cmp.size())
            cmp.insert(it+ans_point,'.');
        count+=(Remove_later(cmp));
        return count;
    }
    
    //字符串去除后导0函数,前导0可以先反转取后导。
    
    string Remove_later(string s)   //删除一个字符串的后倒0
    {
        for(int i=s.size()-1; i>=0; i--)
        {
            if(s[i]=='0')
                s.erase(i);
            else
                break;
        }
        return s;
    }
    View Code

     O(N)找出没有重复的数 (异或,前提是其他数都出现了两次)

    int find(int[] arr){
        int tmp = arr[0];
        for(int i = 1;i < arr.length; i++){
            tmp = tmp ^ arr[i];
        }
        return tmp;
    }
    View Code

    组合数打表(一)

    原理:

    空间:O(nm)

    时间:预处理O(nm)  查询O(1)

    for(int i=0;i<=n;i++){
        c[i][0]=c[i][i]=1;
        for(int j=1;j<i;j++)
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    }
    View Code

    (二)

    原理:费马小定理

    空间:O(n)

    时间:预处理O(n)      查询O(log p)

    ll qpow(ll a,ll b){
        ll ans = 1,base = a;
        while(b){
            if(b&1) ans = ans * base % mod;
            base = base * base % mod;
            b>>=1;
        }
        return ans;
    }
    void init(){
        f[0]=1;
        for(int i=1;i<=2e5;i++){
            f[i]=f[i-1]*i%mod;
        }
    }
    ll C(ll n,ll m){
        if(n<m) return 0;
         return 1ll*f[n]*qpow(f[m],mod-2)%mod*qpow(f[n-m],mod-2)%mod;
    }
    View Code

    (三)lucas

    #define int long long
    int t,n,m,p,f[100005];
    int pow(int x,int y,int p){ //快速幂
        x%=p;
        int ans=1;
        for(int i=y;i;i>>=1,x=x*x%p) if(i&1) ans=ans*x%p;
        return ans;
    }
    int C(int n,int m,int p){ //求组合数
        if(m>n) return 0;
        return ((f[n]*pow(f[m],p-2,p))%p*pow(f[n-m],p-2,p)%p);
    }
    int lucas(int n,int m,int p){ //Lucas定理
        if(!m) return 1;
        return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
    }
    signed main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d%d%d",&n,&m,&p);
            f[0]=1;
            for(int i=1;i<=p;i++)
                f[i]=(f[i-1]*i)%p;
            printf("%lld
    ",lucas(n+m,m,p));
        }
    }
    View Code
  • 相关阅读:
    JavaScript学习总结【5】、JS DOM
    JavaScript学习总结【11】、JS 运动
    JavaScript学习总结【7】、JS RegExp
    JavaScript学习总结【1】、初识JS
    JavaScript学习总结【10】、DOM 事件
    直接选择排序及交换二个数据的实现
    快速排序
    Lucene.net搜索结果排序(单条件和多条件)
    冒泡排序
    直接插入排序的三种实现
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/13121902.html
Copyright © 2011-2022 走看看