数论基础模板

本文提供了多种关于素数处理及数学算法的实现方法,包括素数筛选、区间素数筛选、合数分解、Miller-Rabin素性测试、Pollard's rho因数分解算法、欧拉函数的计算以及扩展欧几里得算法等。

一部分是直接copy别人的,主要是为了之后方便用。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
///素数筛选
const int MAXN=1000010;
int prime[MAXN+5];
void getPrime()
{
    memset(prime,0,sizeof(prime));
    for(int i=2;i<=MAXN;i++)
    {
        if(!prime[i])prime[++prime[0]]=i;
        for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++)
        {
            prime[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
}
///大区间素数筛选(POJ 2689)//来自kuangbin
/*
* POJ 2689 Prime Distance
* 给出一个区间 [L,U],找出区间内容、相邻的距离最近的两个素数和距离最远的两个素数。
* 1<=L<U<=2,147,483,647 区间长度不超过 1,000,000
* 就是要筛选出 [L,U] 之间的素数
*/
#include<bits/stdc++.h>
const int MAXN=100010;
int prime[MAXN+1];
void getPrime(){
    memset(prime,0,sizeof(prime));
    for(int i=2;i<=MAXN;i++){
        if(!prime[i])prime[++prime[0]]=i;
        for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++){
            prime[prime[j]*i]=1;
            if(i%prime[j]==0)break;
        }
    }
}
bool notprime[1000010];
int prime2[1000010];
void getPrime2(int L,int R){
    memset(notprime,false,sizeof(notprime));
    if(L<2)L=2;
    for(int i=1;i<=prime[0]&&(long long)prime[i]*prime[i]<=R;i++){
        int s=L/prime[i]+(L%prime[i]>0);
        if(s==1)s=2;
        for(int j=s;(long long)j*prime[i]<=R;j++)
        if((long long)j*prime[i]>=L)
            notprime[j*prime[i]-L]=true;
    }
    prime2[0]=0;
    for(int i=0;i<=R-L;i++)
    if(!notprime[i])
    prime2[++prime2[0]]=i+L;
}
int main(){
    getPrime();
    int L,U;
    while(scanf("%d%d",&L,&U)==2)
    {
        getPrime2(L,U);///区间内的素数都放在prime2中
        if(prime2[0]<2)
        printf("There are no adjacent primes.\n");
        else
        {
            int x1=0,x2=100000000,y1=0,y2=0;
            for(int i=1;i<prime2[0];i++)
            {
                if(prime2[i+1]-prime2[i]<x2-x1)
                {
                    x1=prime2[i];
                    x2=prime2[i+1];
                }
                if(prime2[i+1]-prime2[i]>y2-y1)
                {
                    y1=prime2[i];
                    y2=prime2[i+1];
                }
            }
            printf("%d,%dare closest,%d,%dare most distant.\n",x1,x2,y1,y2);
        }
    }
}
///合数分解
ll factor[100][2];
int fatCnt;
int getFactors(ll x)
{
    fatCnt=0;
    ll tmp=x;
    for(int i=1;prime[i]<=tmp/prime[i];i++)
    {
        factor[fatCnt][1]=0;
        if(tmp%prime[i]==0)
        {
            factor[fatCnt][0]=prime[i];
            while(tmp%prime[i]==0)
            {
                factor[fatCnt][1]++;
                tmp/=prime[i];
            }
            fatCnt++;
        }
    }
    if(tmp!=1)
    {
        factor[fatCnt][0]=tmp;
        factor[fatCnt++][1]=1;
    }
    return fatCnt;
}
///Miller_Rabin判断大数是否为素数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MT 5
int prime[] = {2, 3, 7, 61, 24251};
ll mulmod(ll a, ll b, ll k)///a*b相乘爆long long的话就要用快速乘了
{
    return (a*b)%k;
}
ll powermod(ll a, ll b, ll k)
{
    ll re = 1, temp = a;
    while(b)
    {
        if (b & 1) re = mulmod(re, temp, k);
        temp = mulmod(temp, temp, k);
        b >>= 1;
    }
    return re;
}
int TwiceDetect(ll a, ll b, ll k) {
    int t = 0;
    ll x, y;
    while ((b & 1) == 0)
    {
        b >>= 1;
        t++;
    }
    y = x = powermod(a, b, k);
    while (t--)
    {
        y = mulmod(x, x, k);
        if (y == 1 && x != 1 && x != k - 1)
            return 0;
        x = y;
    }
    return y;
}
bool Miller_Rabin(ll n)
{
    int i;
    ll tmp;
    for (i = 0; i < MT; i++) {
        tmp = prime[i];
        if (n == prime[i]) return true;
        if (TwiceDetect(tmp, n - 1, n) != 1)
            break;
    }
    return (i == MT);
}
int main()
{
    ll n;
    while (scanf("%lld", &n) == 1)
    {
        if ((n > 1) && Miller_Rabin(n)) {
            printf("YES\n");
        }else {
            printf("NO\n");
        }
    }
    return 0;
}
/// pollard_rho 算法进行质因素分解
///kuangbin
//*********************************************
ll factor[100];//质因素分解结果(刚返回时时无序的)
int tol;//质因素的个数,编号 0--tol-1

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;}
    }
}
//对 n 进行素因子分解,存入 factor. k 设置为 107 左右即可
void findfac(ll n,int k){
    if(n == 1)return;
    if(Miller_Rabin(n))
    {
        factor[tol++] = n;
        return;
    }
    ll p = n;
    int c = k;
    while( p >= n)p = pollard_rho(p,c--);//值变化,防止死循环 k
    findfac(p,k);
    findfac(n/p,k);
}
//POJ 1811
//给出一个N(2 <= N < 2^54),如果是素数, 输出"Prime", 否则输出最小的素因子
int main(){
    int T;
    ll n;
    scanf("%d",&T);
    while(T--){
        scanf("%I64d",&n);
        if(Miller_Rabin(n))printf("Prime\n");
        else{
            tol = 0;
            findfac(n,107);
            ll ans = factor[0];
            for(int i = 1;i < tol;i++)
            ans = min(ans,factor[i]);
            printf("%I64d\n",ans);
        }
    }
    return 0;
}
///筛法求欧拉函数
const int N=3e6;
int euler[N+10];
void getEuler()
{
    memset(euler,0,sizeof euler);
    euler[1]=1;
    for(int i=2;i<=N;i++)
    if(!euler[i])
    {
        for(int j=i;j<=N;j+=i)
        {
            if(!euler[j])
                euler[j]=j;
            euler[j]=euler[j]/i*(i-1);
        }
    }
}
///欧拉线性筛
const int N = 2e7+5;
bool flag[N];
int phi[N];
int p[N];
int cnt = 0;
void Get_phi()
{
    cnt = 0;
    memset(flag, true, sizeof(flag));
    phi[1] = 1;
    for(int i=2; i< N; i++)
    {
        if(flag[i])
        {
            p[cnt++] = i;
            phi[i] = i-1;
        }
        for(int j=0; j<cnt; j++)
        {
            if(i*p[j] > N)
                break;
            flag[i*p[j]] = false;
            if(i%p[j] == 0)
            {
                phi[i*p[j]] = p[j] * phi[i];
                break;
            }
            else
                phi[i*p[j]] = (p[j]-1) * phi[i];
        }
    }
}

///求单个欧拉函数
ll eular(ll n)
{
    ll ans=n;
    for(ll 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;
}

int eular(int x)//效率更高点的求单个欧拉函数,需要先筛出质数
{
    int r=x;
    for(int i=1;prime[i]*prime[i]<=x;i++)
    {
        if(x%prime[i]==0)
        {
            r=r-r/prime[i];
            while(x%prime[i]==0)
                x/=prime[i];
        }
    }
    if(x>1)r=r-r/x;
    return r;
}

//小于等于n,与n互质的数的和是  euler(n)*n/2;
//欧拉函数是积性函数——若m,n互质,euler(m*n)=euler(n)*euler(m) 
//当n为奇数时,euler(2*n)=euler(n) 
//若n为质数则,euler(n)=n-1
//若a,m互质,a^phi(m) %m = 1 (欧拉定理)。当m为质数p时,a^(p-1) % p = 1 (费马小定理)。通常利用结论降幂
//p是素数,且n = p^k,那么φ(n) = (p-1)*p^(k-1)
#define MOD 9973
///快速乘
//计算 (a*b)%c, a,b都是long long的数,直接相乘可能溢出的,a,b,c <2^63
ll mult_mod(ll a,ll b,ll c)
{
    a%=c;
    b%=c;
    ll ret=0;
    while(b)
    {
        if(b&1){ret+=a;ret%=c;}
        a<<=1;
        if(a>=c)a%=c;
        b>>=1;
    }
    return ret;
}
///快速幂
ll qmod(ll x,ll p)
{
    ll ans=1;
    while(p)
    {
        if(p&1) ans=ans*x%MOD;
        x=x*x%MOD;
        p/=2;
    }
    return ans;
}
gcd(x^a−1,x^b−1)=x^gcd(a,b)−1
gcd(fib[a],fib[b])=fib[gcd(a,b)]  ///斐波那契数列
///欧几里得x=__gcd(a,b);
///扩展欧几里得
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
ll extend_gcd(ll a,ll b,ll &x,ll &y)
{
    if(a==0&&b==0) return -1;//无最大公约数
    if(b==0){x=1;y=0;return a;}
    ll d=extend_gcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
//扩展欧几里德求ax+by=n 非负解的个数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll gcd(ll a, ll b) {
    return b ? gcd(b, a%b) : a;
}

ll lcm(ll a, ll b) {
    return a / gcd(a,b) * b;
}

ll extend_gcd(ll a,ll b,ll&x,ll&y) {
    if(!b) {
        x = 1;
        y = 0;
        return a;
    }
    ll xt = 0, yt = 0;
    ll d = extend_gcd(b, a % b, xt, yt);
    x = yt;
    y = xt - yt * (a/b);
    return d;
}

ll cal(ll a,ll b,ll n) {
    ll x = 0,y = 0,d;
    d = extend_gcd(a,b,x,y);
    if(n % d != 0) {
        return 0;
    }
    x *= n / d, y *= n / d;
    ll LCM = lcm(a,b);
    ll t1 = LCM / a, t2 = LCM / b;
    if(x<1) {
        ll num = (1-x) / t1;
        x += num * t1;
        y -= num * t2;
        if(x<1) {
            y -= t2;
            x += t1;
        }
    }
    if(y<1) {
        ll num = (1-y) / t2;
        y += num * t2;
        x -= num * t1;
        if(y<1) {
            y += t2;
            x -= t1;
        }
    }
    ll ans = x > 0 && y > 0;
    if(ans) {
        ans += min((x-1) / t1, ((n-1) / b - y) / t2);
        ans += min((y-1) / t2, ((n-1) / a - x) / t1);
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll n,a,b;
        scanf("%lld%lld%lld",&n,&a,&b);
        printf("%lld\n",cal(a,b,n));
    }
    return 0;
}
//求ax+by=c的最小正整数解(x,y)
int main()
{
    LL a, b, c, gcd;

    scanf("%lld%lld%lld", &a, &b, &c);
    gcd = Gcd(a, b);

    if(c % gcd != 0)// 判断是否有解
        printf("Impossible\n");
    else
    {
        ex_gcd(a, b);
        LL x1, y1, b1;
        b1 = b/gcd;
        x1 = (x + b1) * (c/gcd);
        x1 = (x1 % b1 + b1) % b1;// 求解出 x 的 最小正整数解
        y1 = (c - a*x1) / b;

        printf("x = %lld , y = %lld\n", x1, y1);
    }

    return 0;
}
///求逆元
//ax = 1(mod n) 求x
ll mod_reverse(ll a,ll n)
{
    ll x,y;
    ll d=extend_gcd(a,n,x,y);
    if(d==1) return (x%n+n)%n;
    else return -1;
}
int main()
{
    ll B;
    cin>>B;
    cout<<mod_reverse(B,MOD)<<endl;///扩展欧几里得求B的逆元
    cout<<qmod(B,MOD-2)<<endl;///快速幂求B的逆元
    return 0;
}
///中国剩余定理
//一般的要求m[i]两两互质
//x%a[i]=m[i] x解
int CRT(int a[],int m[],int n)
{
    int M=1,ans=0;
    for(int i=1;i<=n;i++)
        M*=m[i];
    for(int i=1;i<=n;i++)
    {
        int x,y;
        int Mi=M/m[i];
        extend_gcd(Mi,m[i],x,y);
        ans=(ans+Mi*x*a[i])%M;
    }
    if(ans<0) ans+=M;
    return ans;
}

//m[i]不满足两两互质的时候
ll Mod;
ll gcd(ll a, ll b)
{
    if(b==0)
        return a;
    return gcd(b,a%b);
}
//a在模n乘法下的逆元,没有则返回-1
ll inv(ll a, ll n)
{
    ll x,y;
    ll t = extend_gcd(a,n,x,y);
    if(t != 1)
        return -1;
    return (x%n+n)%n;
}
//将两个方程合并为一个
bool merge(ll a1, ll n1, ll a2, ll n2, ll& a3, ll& n3)
{
    ll d = gcd(n1,n2);
    ll c = a2-a1;
    if(c%d)
        return false;
    c = (c%n2+n2)%n2;
    c /= d;
    n1 /= d;
    n2 /= d;
    c *= inv(n1,n2);
    c %= n2;
    c *= n1*d;
    c += a1;
    n3 = n1*n2*d;
    a3 = (c%n3+n3)%n3;
    return true;
}
//求模线性方程组x=ai(mod ni),ni可以不互质
ll CRT(int len, ll* a, ll* n)
{
    ll a1=a[0],n1=n[0];
    ll a2,n2;
    for(int i = 1; i < len; i++)
    {
        ll aa,nn;
        a2 = a[i],n2=n[i];
        if(!merge(a1,n1,a2,n2,aa,nn))
            return -1;
        a1 = aa;
        n1 = nn;
    }
    Mod = n1;
    return (a1%n1+n1)%n1;
}
///组合数
const int N=1e5;
const ll mod=100000007;
ll qmod(ll x,ll p)
{
    ll ans=1;
    while(p)
    {
        if(p&1) ans=ans*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return ans;
}

ll fac[N+10],inv[N+10];
void init()
{
    fac[0]=1;
    for(int i=1;i<=N;i++)
    {
        fac[i]=fac[i-1]*i%mod;
        if(fac[i]==0)
        fac[i]=fac[i]+mod;
    }
    inv[N]=qmod(fac[N],mod-2);//N!的逆元
    for(int i=N-1;i;i--)
        inv[i]=(i+1)*inv[i+1]%mod;
}
ll C(ll n,ll m)
{
    if(m>n) return 0;
    return fac[n]*inv[n-m]%mod*inv[m]%mod;
}
inv[0]=inv[1]=1;
for(int i = 2; i < N; ++i)
    inv[i] = (mod - mod/i) * inv[mod%i] % mod;//线性求i的逆元
//大数组合数,卢卡斯定理
typedef long long ll;
ll  n, m, p;
ll extend_gcd(ll a,ll b,ll &x,ll &y)
{
   if(b==0) { x=1, y=0; return a; }
   ll ret= extend_gcd(b,a%b,y,x);
   y-= a/b*x;
   return ret;
}
ll Inv(ll a,int m)
{
   ll d,x,y,t= (ll)m;
   d= extend_gcd(a,t,x,y);
   if(d==1) return (x%t+t)%t;
   return -1;
}
ll C(ll n, ll m, ll p)
{
    ll a=1, b=1;
    if(m>n) return 0;
    while(m)
    {
        a=(a*n)%p;
        b=(b*m)%p;
        m--;
        n--;
    }
    return (ll)a*Inv(b,p)%p;
}
int Lucas(ll n, ll m, ll p)
{
    if(m==0) return 1;
    return (ll)C(n%p,m%p,p)*(ll)Lucas(n/p,m/p,p)%p;
}

int main()
{
    int  T;
    cin >> T;
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&p);
        printf("%d\n",Lucas(n,m,p));
    }
    return 0;
}
<think>首先,用户查询是:“我想查找ACM数论相关的代码模板 请问ACM数论代码模板”。我需要基于系统级指令和用户提供的引用来回答。 系统级指令关键点: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 引用末尾添加标识如[^1]。 用户提供了几个引用: - [^1]:关于模逆元的计算,使用快速幂或扩展欧几里得算法。 - [^2]:莫比乌斯反演的题目和公式。 - [^3]:预处理阶乘和逆元,用于组合数的计算。 - [^4]:欧拉函数的定义、性质和计算算法。 用户的上一次查询是“查找ACM数论相关的代码模板”,所以我需要提供一个清晰的、结构化的回答,涵盖常见的ACM数论模板。 核心元素: - **模逆元计算**:快速幂方法(qmi)和扩展欧几里得方法。 - **组合数计算**:预处理阶乘和其逆元。 - **欧拉函数**:朴素方法和线性筛法。 - **快速幂算法**:用于快速计算幂模素数。 - **其他常见模板**:如最大公约数(GCD)、质因数分解、线性筛质数等。 由于引用中没有提到所有,我应该补充常见模板,确保回答全面但基于引用优先。 结构回答: 1. **引言**:简要介绍ACM数论常见算法。 2. **核心模板**:逐一列出代码模板3. **格式**:代码块使用Markdown格式,数学表达式正确。 4. **引用**:在相关部分添加引用标识。 5. **相关问题**:结束时生成相关问题。 列出模板: - **快速幂算法**:引用[^1]和[^3]中都有。 - **模逆元计算**:引用[^1]。 - **组合数计算**:引用[^3]。 - **欧拉函数计算**:引用[^4]。 - **其他**:GCD、线性筛质数、扩展欧几里得(引用[^1]中提到)。 添加扩展欧几里得,因为它用于模逆元。 回答结构: - 逐步呈现每个模板。 - 每个模板先简短描述,然后代码块。 - 确保LaTeX正确。 数学表达式: - 行内:如$gcd(n, p) = 1$。 - 独立:如欧拉函数性质。 生成相关问题: - 如ACM数论的应用、优化等。 最终输出: - 中文回答。 - 相关问题列表。 </think>以下是针对ACM数论常见代码模板的整理。ACM数论题目通常涉及质数、模运算、组合数学等核心算法。我基于您提供的引用内容(参考[^1][^2][^3][^4]),并结合ACM竞赛的常见需求,总结了以下关键模板模板均使用C++语言实现,并确保语法正确。每个模板包括简要说明、适用条件和代码实现。 ### 1. **快速幂算法** 快速幂用于高效计算 $a^k \mod p$,时间复杂度 $O(\log k)$。适用条件:$p$ 为质数(非质数时需用扩展欧几里得)。 ```cpp typedef long long LL; LL qmi(LL a, LL k, LL p) { // a: 底数, k: 指数, p: 模数 LL res = 1 % p; while (k) { if (k & 1) res = res * a % p; a = a * a % p; k >>= 1; } return res; } /* 示例:计算 2^100 mod 1000000007 qmi(2, 100, 1000000007); */ ``` ### 2. **模逆元计算** 模逆元用于求解 $n^{-1} \mod p$(即 $n \cdot inv \equiv 1 \mod p$)。方法包括快速幂逆元(要求 $p$ 质数且 $gcd(n, p) = 1$)和扩展欧几里得逆元(通用)。 - **快速幂逆元**(引用[^1]): ```cpp LL inv(LL n, LL p) { // n: 待求逆元的数, p: 模数 return qmi(n, p - 2, p); // 利用费马小定理 } ``` - **扩展欧几里得逆元**(引用[^1]): ```cpp LL exgcd(LL a, LL b, LL &x, LL &y) { // 求解 ax + by = gcd(a, b),返回gcd if (b == 0) { x = 1, y = 0; return a; } LL d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } LL inv_exgcd(LL n, LL p) { LL x, y; exgcd(n, p, x, y); // 解 nx + py = 1 return (x % p + p) % p; // 确保非负 } ``` ### 3. **组合数计算** 预处理阶乘和阶乘逆元,用于快速计算 $C_a^b \mod p$(如组合数)。时间复杂度:预处理 $O(n)$,查询 $O(1)$。适用条件:$p$ 质数且 $a, b \leq N$($N$ 为预处理上限)(引用[^3])。 ```cpp const int N = 1000010; // 预处理上限 const int mod = 998244353; // 常用模数,可替换 LL fact[N], infact[N]; // fact[i]: i的阶乘 mod p; infact[i]: i的阶乘逆元 mod p // 预处理函数 void init_comb() { fact[0] = infact[0] = 1; for (int i = 1; i < N; i++) { fact[i] = fact[i - 1] * i % mod; infact[i] = infact[i - 1] * qmi(i, mod - 2, mod) % mod; // 使用快速幂求逆元 } } // 计算组合数 C(a, b) mod p LL comb(int a, int b) { if (b < 0 || b > a) return 0; return fact[a] * infact[b] % mod * infact[a - b] % mod; } ``` ### 4. **欧拉函数** 欧拉函数 $\phi(n)$ 计算小于等于 $n$ 且与 $n$ 互质的数的个数。常用方法:朴素法 ($O(\sqrt{n})$ ) 和线性筛法 ($O(n \log \log n)$ )(引用[^4])。 - **朴素法**(单次查询): ```cpp int euler(int n) { int res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res / i * (i - 1); // 防止溢出 while (n % i == 0) n /= i; } } if (n > 1) res = res / n * (n - 1); return res; } ``` - **线性筛法**(批量预处理): ```cpp const int Max = 1000010; // 预处理上限 int euler_phi[Max]; void init_euler() { for (int i = 1; i < Max; i++) euler_phi[i] = i; for (int i = 2; i < Max; i++) { if (euler_phi[i] == i) { // i 是质数 for (int j = i; j < Max; j += i) { euler_phi[j] = euler_phi[j] / i * (i - 1); // 更新欧拉函数值 } } } } ``` ### 5. **莫比乌斯反演相关** 莫比乌斯函数常用于处理数论求和问题(如引用[^2]中 $\sum \text{lcm}(a_i, a_j)$)。包括莫比乌斯函数 $\mu(n)$ 的预处理。 ```cpp const int MAXN = 1000010; int mu[MAXN]; // 莫比乌斯函数数组 vector<int> primes; // 存储质数 bool is_prime[MAXN]; void init_mobius() { fill(is_prime, is_prime + MAXN, true); mu[1] = 1; for (int i = 2; i < MAXN; i++) { if (is_prime[i]) { primes.push_back(i); mu[i] = -1; // 质数的莫比乌斯函数值为 -1 } for (int j = 0; j < primes.size() && i * primes[j] < MAXN; j++) { is_prime[i * primes[j]] = false; if (i % primes[j] == 0) { mu[i * primes[j]] = 0; // 有平方因子 break; } else { mu[i * primes[j]] = -mu[i]; // 积性函数性质 } } } } ``` ### 6. **其他基础模板** - **最大公约数 (GCD)**: ```cpp LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } ``` - **最小公倍数 (LCM)**: ```cpp LL lcm(LL a, LL b) { return a / gcd(a, b) * b; // 避免溢出 } ``` - **质数筛法 (埃氏筛)**: ```cpp const int MAX = 1000010; bool is_prime[MAX]; void init_primes() { fill(is_prime, is_prime + MAX, true); is_prime[0] = is_prime[1] = false; for (int i = 2; i * i < MAX; i++) { if (is_prime[i]) { for (int j = i * i; j < MAX; j += i) { is_prime[j] = false; } } } } ``` ### 注意事项 - 所有模板均假设模数 $p$ 在合理范围内(通常 $p \leq 10^9$),并使用 `long long` 防溢出。 - 在ACM中,欧拉定理和指数降幂公式可用于优化幂运算(引用[^4]):若 $a$ 和 $n$ 互质,则 $a^k \mod n = a^{k \mod \phi(n)} \mod n$。 - 这些模板覆盖了大部分ACM数论题目,如莫比乌斯反演、组合计数和模方程求解[^1][^2][^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值