“一切都会好起来的。”|

zplqwq

园龄:3年10个月粉丝:25关注:14

2021-09-27 15:38阅读: 233评论: 0推荐: 1

初等数论

前言:

如何评价 OI 逐渐 MO 化。

我数学不是很好,最近学了这玩意,写一篇总结。

Part I 素数筛

  • 埃式筛 Eraosthenes

    • 大概思路:从2开始,由小到大扫描每一个数 x,把他的倍数标记为合数。当扫描到一个数时,若尚未被标记,那么就是质数。
    • 复杂度:O(nloglogn) 接近线性。
    • 代码:
void make_prime()
{
memset(prime,true,sizeof(prime));
prime[0]=prime[1]=false;//0,1都不是素数
int t=sqrt(n);//开根号
for(int i=2;i<=t;i++)
{
if(prime[i])
{
for(int j=2*i;j<=n;j+=i)//加倍
{
prime[j]=false;
}
}
}
return;
}
  • 线性筛

    • 大致思路:从小到大积累质因子
    • 复杂度:O(n)
void init() {
phi[1] = 1;
for (int i = 2; i < MAXN; ++i) {
if (!vis[i]) {
phi[i] = i - 1;
pri[cnt++] = i;
}
for (int j = 0; j < cnt; ++j) {
if (1ll * i * pri[j] >= MAXN) break;
vis[i * pri[j]] = 1;
if (i % pri[j]) {
phi[i * pri[j]] = phi[i] * (pri[j] - 1);
} else {
// i % pri[j] == 0
// 换言之,i 之前被 pri[j] 筛过了
// 由于 pri 里面质数是从小到大的,所以 i 乘上其他的质数的结果一定会被
// pri[j] 的倍数筛掉,就不需要在这里先筛一次,所以这里直接 break
// 掉就好了
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
}
}
}

Part II Prime Numbers and Phi

ϕ(n) 表示 1 n 中与 n 互质的个数。同时也是欧拉函数。

然后有很多好玩的性质,由于我 LATEX 实在不大行就先不写了。

代码:

void euler(int n)
{
for(int i=2;i<=n;i++) ph[i]=i;
for(int i=2;i<=n;i++)
{
if(ph[i]==i)
{
for(int j=i;j<=n;j+=i)
{
ph[j]=ph[j]/i*(i-1);
}
}
}
}

Part III 欧几里得

  • gcd:欧几里得算法,俗称辗转相除。
int gcd(int a,int b)
{
return b ? gcd(b,a%b) : a;
}
  • 扩展欧几里得:对于任意整数 a,b ,存在一对整数 x,y ,满足 ax+by=gcd(a,b) 。不过说句闲话,这个应该裴蜀定理。解这个方程算法被称之为“扩展欧几里得”。
int exgcd(int a,int b,int &x,int &y)
{
if(a==0)
{
x=0;y=1;
return b;
}
int d=exgcd(b%a,a,y,x);
x-=b/a*y;
return d;
}

提一嘴逆元:若整数 b,m 互质,且 b|a,则存在一个整数 x,使得 aba×xm 同余。则称 xb 的模 m 乘法逆元。然后这玩意一般都是用来转换除法的。

Part IIII 同余方程

对于像 ACwing203 这种题直接用欧几里得算法求出一种特解,然后就最小值即可。

中国剩余定理:

直接放代码:

/*long long gcd(LL a,LL b)
{
return b==0?a:gcd(b,a%b);
}*/
#include<cstdio>
#define ll long long
//扩展欧几里得算法
void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(b==0){
d=a;
x=1,y=0;
}
else{//else不能省略
gcd(b,a%b,d,y,x);
y-=(a/b)*x;
}
}
//中国剩余定理
ll China(int n,ll *m,ll *a)
{
ll M=1,d,y,x=0;
for(int i=0;i<n;i++) M*=m[i];
for(int i=0;i<n;i++){
ll w=M/m[i];
gcd(m[i],w,d,d,y);
x=(x+y*w*a[i])%M;
}
return (x+M)%M;
}
ll m[15],a[15];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld%lld",&m[i],&a[i]);
printf("%lld",China(n,m,a));
}

本文作者:zplqwq

本文链接:https://www.cnblogs.com/zplqwq/p/15343263.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   zplqwq  阅读(233)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示