数论常用模板

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <map>
#define int long long
const int maxn=1e4+10;

int mul_mod(int a,int b,int n){
    return a*b%n;
}
//快速幂取模
int pow_mod(int a,int n,int mod){
    if(n==0)return 1;
    int ans=pow_mod(a,n/2,mod);
    ans=ans*ans%mod;
    if(n%2==1)ans=ans*a%mod;
    return ans;
}
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}



//扩展GCD
int ex_gcd(int a,int b,int &x,int &y){
   if(b==0){x = 1;y = 0;return a;}
   int g = ex_gcd(b,a%b,x,y);
   int temp = x;
   x = y;
   y = temp - a/b*y;
   return g;
}
//扩展欧几里得的另一种写法
void ex_gcd(int a,int b,int &d,int &x,int &y){
    //求解ax+by=gcd(a,b)的一组解
    if(!b){
        d=a,x=1,y=0;
    }
    else{
        ex_gcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}


//逆元
int inv(int a,int mod){
   int X,Y;
   int g = ex_gcd(a,mod,X,Y);
   if(g!=1)return -1;
   return (X%mod + mod)%mod;
}
//费马小定理求逆元(质数)
ll poww(ll a,ll b)
{
    b-=2;//费马小定理要减2
    ll res=1;
    while(b)
    {
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}


//a^x=b(mod n),求解x,大步小步算法
int log_mod(int a,int b,int n){
    int m,v,e=1;
    m=(int)sqrt(n+0.5);
    v=inv(pow_mod(a,m,n),n);
    map<int,int>x;
    x[1]=0;
    for(int i=1;i<m;i++){
        e=mul_mod(e,a,n);
        if(!x.count(e))x[e]=i;
    }
    for(int i=0;i<m;i++){
        if(x.count(b))return i*m+x[b];
        b=mul_mod(b,v,n);
    }
    return -1;
}

//中国剩余定理
int china(int n,int *a,int *m){
    int M=1,d,y,x=0;//M为每个m[i]的乘积
    for(int i=1;i<=n;i++){
        M*=m[i];
    }
    for(int i=1;i<=n;i++){
        int w=M/m[i];//求每个wi,还需要求每个wi的逆
        ex_gcd(m[i],w,d,d,y);//因为m[i]与w互素,则求解的是m[i]*d+w*y=1,对m[i]取模后有w*y=1,即y为w的数论倒数
        x=(x+y*w*a[i])%M;
    }
    return (x+M)%M;
}

//可以处理不互素的中国剩余定理
int ex_china(int n,int *C,int *M){
    for(int i = 2;i<=n;i++){
        int M1 = M[i-1],M2 = M[i],C1 = C[i-1],C2 = C[i];
        int g = gcd(M1,M2);
        if((C2-C1)%g)return -1;
        M[i] = M1/g*M2;
        int INV = inv(M1/g,M2/g);
        if(INV==-1)return -1;
        C[i] =  C1 + (INV*((C2-C1)/g))%(M2/g)*M1;
        C[i] = (C[i]%M[i] + M[i])%M[i];
    }
    return C[n];
}

再来个矩阵和矩阵快速幂的模板

typedef long long lint
struct matrix
{
    lint m[10][10];
    matrix()
    {
        memset(m,0,sizeof(m));//注意要清零
    }
};
 
matrix operator * (const matrix & a,const matrix & b)
{
    matrix c;
    for (int i=1; i<=9; i++)
        for (int j=1; j<=9; j++)
        {
            c.m[i][j]=0;
            for (int k=1; k<=9; k++)
                c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;//一般题目都要求要modulo一个数
        }
    return c;
}
 
matrix quick(matrix base,int pow)
{
    matrix a;
    for (int i=1; i<=9; i++) a.m[i][i]=1;//单位阵,矩阵乘法时要用到
    while (pow)
    {
        if (pow&1) a=a*base;
        base=base*base;
        pow>>=1;
    }
    //if (pow==0) return base;
    return a;
}

 

BM模板,用于求解线性递推,注意往vector里面装数至少要是8个,越多越好

模板题:牛客多校第二场B

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <cassert>
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define int long long
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
const int maxn=1028;
ll powmod(ll a,ll b,ll mod) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
// head

ll n,k;
namespace linear_seq {
    const int N=1030;
    ll res[N],base[N],_c[N],_md[N];

    vector<int> Md;
    void mul(ll *a,ll *b,int k) {
        rep(i,0,k+k) _c[i]=0;
        rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
        for (int i=k+k-1;i>=k;i--) if (_c[i])
            rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
        rep(i,0,k) a[i]=_c[i];
    }
    int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
        ll ans=0,pnt=0;
        int k=SZ(a);
        assert(SZ(a)==SZ(b));
        rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
        Md.clear();
        rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
        rep(i,0,k) res[i]=base[i]=0;
        res[0]=1;
        while ((1ll<<pnt)<=n) pnt++;
        for (int p=pnt;p>=0;p--) {
            mul(res,res,k);
            if ((n>>p)&1) {
                for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
                rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
            }
        }
        rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
        if (ans<0) ans+=mod;
        return ans;
    }
    VI BM(VI s) {
        VI C(1,1),B(1,1);
        int L=0,m=1,b=1;
        rep(n,0,SZ(s)) {
            ll d=0;
            rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
            if (d==0) ++m;
            else if (2*L<=n) {
                VI T=C;
                ll c=mod-d*powmod(b,mod-2,mod)%mod;
                while (SZ(C)<SZ(B)+m) C.pb(0);
                rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                L=n+1-L; B=T; b=d; m=1;
            } else {
                ll c=mod-d*powmod(b,mod-2,mod)%mod;
                while (SZ(C)<SZ(B)+m) C.pb(0);
                rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                ++m;
            }
        }
        return C;
    }
    int gao(VI a,ll n) {
        VI c=BM(a);
        c.erase(c.begin());
        rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
        return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
    }
};

//扩展GCD
int ex_gcd(int a,int b,int &x,int &y){
   if(b==0){x = 1;y = 0;return a;}
   int g = ex_gcd(b,a%b,x,y);
   int temp = x;
   x = y;
   y = temp - a/b*y;
   return g;
}
//扩展欧几里得的另一种写法
void ex_gcd(int a,int b,int &d,int &x,int &y){
    //求解ax+by=gcd(a,b)的一组解
    if(!b){
        d=a,x=1,y=0;
    }
    else{
        ex_gcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}
//逆元
int inv(int a,int mod){
   int X,Y;
   int g = ex_gcd(a,mod,X,Y);
   if(g!=1)return -1;
   return (X%mod + mod)%mod;
}
int a[maxn];
int sum[maxn];
signed main() {
    /*push_back 进去前 8~10 项左右、最后调用 gao 得第 n 项*/
    int T;
    scanf("%d",&T);
    while(T--){
        vector<int>v;
        scanf("%lld%lld",&k,&n);
        int invk=inv(k,mod);
        if(n==-1){
            int tmp=inv(k+1,mod);
            printf("%lld\n",2*tmp%mod);
            continue;
        }
        a[0]=1;
        for(int i=1;i<=50;i++){
            a[i]=0;
            for(int j=1;j<=min(i,k);j++){
                a[i]+=a[i-j]*invk%mod;
                a[i]%=mod;
            }
        }
        for(int i=1;i<=50;i++){
            v.push_back(a[i]);
        }
        printf("%lld\n",linear_seq::gao(v,n-1)%mod);
    }
    return 0;
}

这个题就往里面扔了2*k+2个数

 

自适应辛普森公式求数值积分

//黑匣子调用:

//先修改函数 double F(double x){}

//然后ans = ars(a, b, eps);

double F(double x){
    return 1;
}
double simpson(double a, double b){
    double c = a + (b-a)/2.0;
    return (F(a) +4*F(c) + F(b)) * (b-a) / 6.0;
}
double asr(double a, double b, double eps, double A){
    double c = a + (b-a) / 2.0;
    double L = simpson(a, c), R = simpson(c, b);
    if(fabs(L+R-A) <= 15*eps) return L+R+(L+R-A)/15.0;
    return asr(a, c, eps/2.0, L) + asr(c, b, eps/2.0, R);
}
double asr(double a, double b, double eps){
    return asr(a, b, eps, simpson(a,b));
}

莫比乌斯函数和它的前缀和

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <queue>
#include <vector>
#include <iomanip>
#define int long long
using namespace std;

const int maxn=1e5+10;
int vis[maxn];
int prime[maxn],tot;
int mu[maxn];//莫比乌斯函数
int sum[maxn];//莫比乌斯函数前缀和
void init(){
    memset(vis,0,sizeof(vis));
    tot=0;
    mu[1]=1;
    for(int i=2;i<maxn;i++){
        if(!vis[i]){
            prime[++tot]=i;
            mu[i]=-1;//素数的话就是-1
        }
        for(int j=1;j<=tot;j++){
            if(i*prime[j]>=maxn){
                break;
            }
            vis[i*prime[j]]=1;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            else{
                mu[i*prime[j]]=-mu[i];//多了个质因子,多个-1
            }
        }
    }
    sum[0]=0;
    for(int i=1;i<maxn;i++){
        sum[i]=sum[i-1]+mu[i];
    }
}

 

大质数的质因子分解——Pollard_rho算法

#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef unsigned long long LL;
std::mt19937 mt_rd(std::chrono::system_clock::now().time_since_epoch().count());//дицК
const LL NUM=10;//运算次数,Miller_Rabin算法为概率运算,误判率为2^(-NUM);
unordered_map<LL,int> mp;
int num[100];
LL t,f[100];
/*
struct ios {
    inline char read(){
        static const int IN_LEN=1<<18|1;
        static char buf[IN_LEN],*s,*t;
        return (s==t)&&(t=(s=buf)+fread(buf,1,IN_LEN,stdin)),s==t?-1:*s++;
    }

    template <typename _Tp> inline ios & operator >> (_Tp&x){
        static char c11,boo;
        for(c11=read(),boo=0;!isdigit(c11);c11=read()){
            if(c11==-1)return *this;
            boo|=c11=='-';
        }
        for(x=0;isdigit(c11);c11=read())x=x*10+(c11^'0');
        boo&&(x=-x);
        return *this;
    }
}io;
*/

LL mul_mod(LL a,LL b,LL n)//求a*b%n,由于a和b太大,需要用进位乘法
{
    a=a%n;
    b=b%n;
    LL s=0;
    while(b)
    {
        if(b&1)
            s=(s+a)%n;
        a=(a<<1)%n;
        b=b>>1;
    }
    return s;
}
LL pow_mod(LL a,LL b,LL n)//求a^b%n
{
    a=a%n;
    LL s=1;
    while(b)
    {
        if(b&1)
            s=mul_mod(s,a,n);
        a=mul_mod(a,a,n);
        b=b>>1;
    }
    return s;
}
bool check(LL a,LL n,LL r,LL s)
{
    LL ans,p,i;
    ans=pow_mod(a,r,n);
    p=ans;
    for(i=1;i<=s;i++)
    {
        ans=mul_mod(ans,ans,n);
        if(ans==1&&p!=1&&p!=n-1)return true;
        p=ans;
    }
    if(ans!=1)return true;
    return false;
}
bool Miller_Rabin(LL n)//Miller_Rabin算法,判断n是否为素数
{
    if(n<2)return false;
    if(n==2)return true;
    if(!(n&1))return false;
    LL i,r,s,a;
    r=n-1;s=0;
    while(!(r&1)){r=r>>1;s++;}
    for(i=0;i<NUM;i++)
    {
        a=mt_rd()%(n-1)+1;
        if(check(a,n,r,s))
            return false;
    }
    return true;
}
LL gcd(LL a,LL b)
{
    for(;a>0&&b>0;a>b?a%=b:b%=a);
    return a+b;
}
LL Pollard_rho(LL n,LL c)//Pollard_rho算法,找出n的因子
{
    LL i=1,j,k=2,x,y,d,p;
    x=mt_rd()%n;
    y=x;
    while(true)
    {
        i++;
        x=(mul_mod(x,x,n)+c)%n;
        if(y==x)return n;
        if(y>x)p=y-x;
        else p=x-y;
        d=gcd(p,n);
        if(d!=1&&d!=n)return d;
        if(i==k)
        {
            y=x;
            k+=k;
        }
    }
}
void find(LL n)//找出n的所有因子
{
    if(Miller_Rabin(n))
    {
        f[t++]=n;//保存所有因子
        return;
    }
    LL p=n;
    while(p>=n)p=Pollard_rho(p,mt_rd()%(n-1)+1);//由于p必定为合数,所以通过多次求解必定能求得答案
    find(p);
    find(n/p);
}
int main()
{
    srand(time(NULL));//随机数设定种子
    LL n;
    int T,ans;
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--){
        cin>>n;
        t=0;
        find(n);
        sort(f,f+t);
        mp.clear();
        ans=1000;
        for(int i=0;i<t;++i){
            mp[f[i]]++;
        }
        for(int i=0;i<t;++i){
            ans=min(ans,mp[f[i]]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

欧拉函数前缀和

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

const int maxn=1e6+10;
int phi[maxn];
int prime[maxn],tot;
int vis[maxn];
void init(){
    memset(vis,0,sizeof(vis));
    tot=0;
    phi[1]=1;
    for(int i=2;i<maxn;i++){
        if(!vis[i]){
            prime[++tot]=i;
            phi[i]=i-1;
        }
        for(int j=1;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]*(prime[j]-1);
            }
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值