模板库(二) - 数论算法模板

写在前面

模板库”这一系列文章用来复习OIOIOI模板
由于时间原因,作者无法一一亲自调试其中的程序,也因如此,有一部分程序来自于互联网,如果您觉得这侵犯了您的合法权益,请联系(QQ2068926345)(QQ2068926345)(QQ2068926345)删除。
对于给您造成的不便和困扰,我表示深深的歉意。
本系列文章仅用于学习,禁止任何人或组织用于商业用途。
本系列文章中,标记*的为选学算法,在NOIPNOIPNOIP中较少涉及。

数论算法模板

快速幂

【简介】

顾名思义,快速幂就是快速算底数的次幂。其时间复杂度为Θ(logn)Θ(logn)Θ(logn),与朴素的相比效率有了极大的提高。

【代码实现】
#include<cstdio>
int b,p,mod;
inline int Fast_pow(long long b,int p){
    long long ans=1;
    while(p){
        if(p&1) ans=ans*b%mod;
        b=b*b%mod;p>>=1;
    }
    return ans;
}
int main(){
    scanf("%d%d%d",&b,&p,&mod);
    printf("%d^%d mod %d=%d",b,p,mod,Fast_pow(b,p));
    return 0; 
}

复杂度Θ(logn)Θ(logn)Θ(logn)


欧几里得算法

【简介】

欧几里德算法又称辗转相除法,是指用于计算两个正整数的最大公约数。应用领域有数学和计算机两个方面。计算公式。

【代码实现】
#include<cstdio>
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d",gcd(a,b));
}

复杂度Θ(logn)Θ(logn)Θ(logn)


扩展欧几里得算法

【简介】

扩展欧几里德算法是用来在已知求解一组,使它们满足贝祖等式: (解一定存在,根据数论中的相关定理)。扩展欧几里德常用在求解模线性方程及方程组中。

【代码实现】
#include<cstdio> 
int exgcd(int a,int b,int &x,int &y){
    if(!b)x=1,y=0;
    else exgcd(b,a%b,y,x),y-=x*(a/b);
}
int main(){
    int a,b,x,y;
    scanf("%d%d",&a,&b);
    exgcd(a,b,x,y);
    printf("%d",(x%b+b)%b);
    return 0;
}

复杂度Θ(logn)Θ(logn)Θ(logn)


逆元

【简介】

乘法逆元,是指数学领域群中任意一个元素,都在中有唯一的逆元,具有性质,其中为该群的单位元。

【代码实现】
方法1:求单个逆元
#include<cstdio>
int n,mod;
inline int Fast_pow(long long b,int p){
    long long ans=1;
    while(p){
        if(p&1) ans=ans*b%mod;
        b=b*b%mod;p>>=1;
    }
    return ans;
}
int main(){
    scanf("%d%d",&n,&mod);
    printf("%d",Fast_pow(n,mod-2);
    return 0; 
}

复杂度Θ(logn)Θ(logn)Θ(logn)

方法2: 线性求逆元
#include<cstdio>
long long a[100007]={0,1};
int main(){
    int n,p;
    scanf("%d%d",&n,&p);
    for(int i=2;i<=n;i++) a[i]=(p-(p/i))*a[p%i]%p;
    for(int i=1;i<=n;i++) printf("%lld\n",a[i]);
    return 0;
}

复杂度Θ(n)Θ(n)Θ(n)


筛法求积性函数

【简介】

筛法是一种简单检定素数的算法。据说是古希腊的埃拉托斯特尼(Eratosthenes(Eratosthenes(Eratosthenes,约公元前274~194274~194274194年)发明的,又称埃拉托斯特尼筛法(sieve(sieve(sieve ofofof Eratosthenes)Eratosthenes)Eratosthenes),后来扩展到利用筛法求积性函数。

【一些性质】

积性函数:对于函数f(n)f(n)f(n),若满足对任意互质的数字aaabbba∗b=na*b=nab=n,且f(n)=f(a)∗f(b)f(n)=f(a)*f(b)f(n)=f(a)f(b),那么称函数fff为积性函数。
狄利克雷卷积:对于函数fffggg,定义它们的卷积为(f∗g)(n)=∑d∣nf(d)g(nd)(f*g)(n)=\sum_{d|n}f(d)g(nd)(fg)(n)=dnf(d)g(nd)

两个积性函数的狄利克雷卷积仍为积性函数。
积性函数都可以用线性筛筛出来

【代码实现】
方法1
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int is_not[10000007]={1,1};
void prime(int n){
    int m=sqrt(n);
    for(int i=2;i<=m;i++)
        if(!shu[i])for(int j=i*i;j<=n;j+=i)shu[j]=1;	
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    prime(N);
    for(int i=1;i<=m;i++)scanf("%d",&a),printf(shu[a]?"No\n":"Yes\n");
    return 0;
}

复杂度Θ(Θ(Θ(nnn logloglog logloglog n)n)n)

方法2
#include<cstdio>
bool is_not[10000007]={1,1};
int prime[664579+7],n,m,a,cnt;
void Prime(int n){
    for(int i=2;i<=n;++i){
        if(!is_not[i])prime[++cnt]=i;
        for(int j=1;j<=cnt && prime[j]*i<=n;++j){
            is_not[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    Prime(n);
    for(int i=1;i<=m;++i)scanf("%d",&a),printf(is_not[a]?"No\n":"Yes\n");
    return 0;
}

复杂度Θ(n)Θ(n)Θ(n)


【利用筛法求一些常见的积性函数】

复杂度Θ(n)Θ(n)Θ(n)

莫比乌斯函数
inline void get_mu(int N){
    is_not[1]=1;mu[1]=1;
    for(int i=2;i<=N;++i){
        if(!is_not[i])prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt && i*prime[j]<=N;++j){
            is_not[i*prime[j]]=1;
            if(i%prime[j]) mu[i*prime[j]]=-mu[i];
            else{mu[i*prime[j]]=0;break;}
        }
    }
}
欧拉函数
void getphi(){
    phi[1]=1;
    for(int i=2;i<=N;++i){
        if(!is_not[i])prime[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt,i*prime[j]<=N;++j){
            is_not[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);
        }
    }
}
约数个数
is_not[1]=1,d[1]=1;
for(int i=2;i<=N;++i){
    if(!is_not[i]){
        prime[++cnt]=i;
        d[i]=2;pred[i]=1;
    }
    for(int j=1;j<=num&&i*prime[j]<=N;++j){
        is_not[i*prime[j]]=1;
        if(i%prime[j])d[i*prime[j]]=d[i]*d[prime[j]],pred[i*prime[j]]=1;
        else{
            pred[i*prime[j]]=pred[i]+1;
            d[i*prime[j]]=d[i]/(pred[i]+1)*(pred[i]+2);
            break;
        }
    }
}
约数的和
void Prepare(){
    is_not[1]=1;f[1]=mu[1]=1;
    for(int i=2;i<=N;++i){
        if(!isprime[i]){
            prime[++cnt]=i;f[i]=i+1;mu[i]=-1;
            sumd[i]=1+i;powd[i]=i;
        }
        for(int j=1;j<=num&&i*prime[j]<N;++j){
            is_not[i*prime[j]]=1;
            if(i%prime[j]){
                sumd[i*prime[j]]=prime[j]+1;
                powd[i*prime[j]]=prime[j];
                f[i*prime[j]]=f[i]*f[prime[j]];
            }
            else{
                powd[i*prime[j]]=powd[i]*prime[j];
                sumd[i*prime[j]]=sumd[i]+powd[i*prime[j]];
                f[i*prime[j]]=f[i]/sumd[i]*sumd[i*prime[j]];
                break;
            }
        }
    }
}

*中国剩余定理

【简介】

中国剩余定理是中国古代求解一次同余式组的方法。是数论中一个重要定理。又称中国余数定理。一元线性同余方程组问题最早可见于中国南北朝时期(((公元5世纪)))的数学著作《孙子算经》卷下第二十六题,叫做“物不知数”问题。
OIOIOI中,中国剩余定理主要解决以下问题:

{x≡a1(mod m1)x≡a2(mod m2)x≡a3(mod m3)  ⋯x≡an(mod mn)\begin{cases} x≡a_1(mod\ m_1)\\ x≡a_2(mod\ m_2)\\ x≡a_3(mod\ m_3)\\ \ \ \cdots\\ x≡a_n(mod\ m_n) \end{cases}xa1(mod m1)xa2(mod m2)xa3(mod m3)  xan(mod mn)

【代码实现】
#include<cstdio>
typedef long long ll;
using namespace std;
ll a[17],b[17],n;
ll exgcd(ll a,ll b,ll &x,ll &y) {
    if(!b){x=1;y=0;return a;}
    long long q=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return q;
}
ll china() {
    ll M=1,res=0;
    for(int i=1;i<=n;i++) M*=a[i];
    for(int i=1;i<=n;i++){
        ll m=M/a[i],p,y;
        ll d=exgcd(m,a[i],p,y);
        res=(res+m*p*b[i])%M;
    }
    if(res<0) res+=M;
    return res;
} 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i],&b[i]);
    printf("%lld",china());
}

复杂度Θ(nΘ(nΘ(n logn)logn)logn)


*BSGS

【简介】

大步小步法(Baby−Step−Giant−Step,简称BSGS)(Baby-Step-Giant-Step,简称BSGS)(BabyStepGiantStepBSGS),可以较高效的求解形如Ax≡B(modA^x≡B(modAxB(mod C)(CC)(CC)(C是素数)))的同余方程。

【代码实现】
#include<cstdio>
#include<map>
#include<cmath>
using namespace std;
__int128 FastPow(__int128 a,__int128 k,__int128 p){
    __int128 ans=1;
    while(k)
    {
        if(k&1) (ans*=a)%=p;
        (a*=a)%=p;
        k>>=1;
    }
    return ans;
}
__int128 BSGS(__int128 a,__int128 b,__int128 p)
{
    map<__int128,__int128>hash;
    hash.clear();
    b%=p;
    __int128 t=(__int128)sqrt((double)p)+1;
    for(__int128 j=0;j<t;j++)
    {
        __int128 val=b*FastPow(a,j,p)%p;
        hash[val]=j;
    }
    a=FastPow(a,t,p);
    if(!a)return(b==0)?1:-1;
    for(__int128 i=0;i<=t;i++)
    {
        __int128 val=FastPow(a,i,p);
        __int128 j=hash.find(val)==hash.end()?-1:hash[val];
        if(j>=0&&i*t-j>=0) return i*t-j;
    }
    return -1;
}
__int128 k,m;
int main(){
    scanf("%lld%lld",&k,&m);
    __int128 ans=BSGS(10,(9*k+1)%m,m);
    printf("%lld",ans);
    return 0;
}

复杂度Θ(C)Θ(\sqrt C)Θ(C)


除法分块

【简介】

求解类似于∑i=1nf(i)[ni]\sum_{i=1}^{n}f(i)[\frac{n}{i}]i=1nf(i)[in]的算式。其中,f(i)f(i)f(i)应可以快速计算前缀和。

【代码实现】
#include<cstdio>
int main(){
    long long n,k,ans=0;
    scanf("%lld%lld",&n,&k);
    for(long long l=1,r,t;l<=n;l=r+1)
        r=(t=k/l)?std::min(k/t,n):n,
        ans+=t*(r-l+1)*(r+l)>>1;
    printf("%lld",n*k-ans);
    return 0;
}

复杂度Θ(n)Θ(\sqrt n)Θ(n)


*Pollard-Rho算法

【简介】

有一类问题,要求我们将一个正整数,分解为两个非平凡因子的乘积x=abx=abx=ab
显然我们需要先检测是否为素数如果是素数将无解,可以使用Miller−RabinMiller-RabinMillerRabin算法来进行测试。
Pollard−RhoPollard-RhoPollardRho是一个非常玄学的方式,用于在O(n4)O(\sqrt[4]{n})O(4n)的期望时间复杂度内计算合数nnn的某个非平凡因子。事实上算法导论给出的是O(p)O(\sqrt p)O(p)pppnnn的某个最小因子,满足pppnp\frac n ppn互质。但是这些都是期望,未必符合实际。但事实上Pollard−RhoPollard-RhoPollardRho算法在实际环境中运行的相当不错。

【代码实现】
#include <cstdio>
#include <algorithm>
#define rep(i, s, t) for(int i = s; i <= t; ++i)
typedef long long ll;
ll H;
ll pls(ll a, ll b, ll p){
    ll res=0;
    for(; b; b>>=1, a=(a+a)%p)
        if(b & 1) res = (res+a)%p;
    return res%p;
}
ll pow(ll a, ll b, ll p){
    ll res = 1;
    for(; b; b>>=1, a=pls(a, a, p))
        if(b&1) res=pls(res, a, p)%p;
    return res % p;
}
bool M(ll p){
    ll x[60] = {0}, s = 20;
    ll rest = p-1, t = 0;
    while(!(rest%2)){
        t++;
        rest >>= 1;
    }
    while(s--){
        ll a = rand()%(p-1)+1;
        x[0] = pow(a, rest, p);
        rep(i, 1, t){
            x[i] = pow(x[i-1], 2, p)%p;
            if(x[i] == 1)
                if((x[i-1] != 1) && (x[i-1] != p-1)) return false;
        }
        if(x[t] ^ 1) return false;
    }
    return true;
}
ll gcd(ll a, ll b){
    while(b){
        ll t = a%b;
        a = b;b = t;
    }
    return a;
}
ll P(ll p){
    ll c = rand()%(p-1)+1, x1 = rand()%(p-1)+1, x2 = x1;
    for(ll i = 2, k = 2; true; ++i){
        x1 = (pls(x1, x1, p) + c)%p;
        ll G = gcd(p, (x2-x1+p)%p);
        if(G > 1 && G < p) return G;
        if(x2 == x1) return p;
        if(i == k) x2 = x1, k <<= 1;
    }
}
void solve(long long n){
    if(n == 1) return;
    if(M(n)){
        H = std::min(H , n);
        return;
    }
    long long p = n;
    while(p == n) p = P(p);
    solve(p);
    solve(n/p);
}
int main(){
    int _;
    scanf("%d", &_);
    while(_--){
        ll p;
        H = 1LL << 54;
        scanf("%lld", &p);
        solve(p);
        if(H ^ p)
            printf("%lld\n", H);
        else puts("Prime");
    }
    return 0;
}

复杂度Θ(n4)Θ(\sqrt[4]{n})Θ(4n)


内容概要:本文深入探讨了Kotlin语言在函数式编程和跨平台开发方面的特性和优势,结合详细的代码案例,展示了Kotlin的核心技巧和应用场景。文章首先介绍了高阶函数和Lambda表达式的使用,解释了它们如何简化集合操作和回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建和平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发和Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程和跨平台开发领域不断完善和发展。; 适合人群:对函数式编程和跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者和中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数和Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解和实践Kotlin的函数式编程特性和跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解和掌握。
内容概要:本文深入探讨了利用历史速度命令(HVC)增强仿射编队机动控制性能的方法。论文提出了HVC在仿射编队控制中的潜在价值,通过全面评估HVC对系统的影响,提出了易于测试的稳定性条件,并给出了延迟参数与跟踪误差关系的显式不等式。研究为两轮差动机器人(TWDRs)群提供了系统的协调编队机动控制方案,并通过9台TWDRs的仿真和实验验证了稳定性和综合性能改进。此外,文中还提供了详细的Python代码实现,涵盖仿射编队控制类、HVC增强、稳定性条件检查以及仿真实验。代码不仅实现了论文的核心思想,还扩展了邻居历史信息利用、动态拓扑优化和自适应控制等性能提升策略,更全面地反映了群体智能协作和性能优化思想。 适用人群:具备一定编程基础,对群体智能、机器人编队控制、时滞系统稳定性分析感兴趣的科研人员和工程师。 使用场景及目标:①理解HVC在仿射编队控制中的应用及其对系统性能的提升;②掌握仿射编队控制的具体实现方法,包括控制器设计、稳定性分析和仿真实验;③学习如何通过引入历史信息(如HVC)来优化群体智能系统的性能;④探索中性型时滞系统的稳定性条件及其在实际系统中的应用。 其他说明:此资源不仅提供了理论分析,还包括完整的Python代码实现,帮助读者从理论到实践全面掌握仿射编队控制技术。代码结构清晰,涵盖了从初始化配置、控制律设计到性能评估的各个环节,并提供了丰富的可视化工具,便于理解和分析系统性能。通过阅读和实践,读者可以深入了解HVC增强仿射编队控制的工作原理及其实际应用效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值