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
  • 相关阅读:
    rs
    stm32f767 usoc3
    stm32f767 RTT 日志
    stm32f767 标准库 工程模板
    stm32f767 HAL 工程模板
    docker tab 补全 linux tab 补全
    docker anconda 依赖 下载 不了
    docker run 常用 指令
    linux scp 命令
    Dockerfile 常用参数说明
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/13121902.html
Copyright © 2011-2022 走看看