数论基础模板

以前写的几个数论模板,整整吧,反正数论这么弱貌似只会gcd的样子...

来,先来gcd

1.

#include<iostream>
#include<cstdio>

using namespace std;

int gcd(int a,int b)
{
    if(b==0) return a;
    else return gcd(b,a%b);
}

int lcm(int x,int y)
{
    return (x*y)/gcd(x,y);
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d %d",gcd(a,b),lcm(a,b));
    return 0;
}

gcd与lcm

扩展欧几里得

求解 x,y的方法的理解

设 a>b。

1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;

2,a>b>0 时

设 ax1+ by1= gcd(a,b);

bx2+ (a mod b)y2= gcd(b,a mod b);

根据朴素的欧几里得原理有 gcd(a,b) = gcd(b,a mod b);

则:ax1+ by1= bx2+ (a mod b)y2;

即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;

也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);

根据恒等定理得:x1=y2; y1=x2- [a / b] *y2;

这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.

2.ex-gcd

/*
扩展欧几里得
ax%b==1  -> ax-by==1
求不定方程的一组解 使x为最小正整数解
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int x,y,gcd;
int Extend(int a,int b)
{
    if(b==0)
      {
          x=1;y=0;
          gcd=a;
      }
    else
      {
          Extend(b,a%b);
          int tmp=x;
          x=y;
          y=tmp-a/b*y;
      }
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    Extend(a,-b);
    x=x*(1/gcd);
    if(x<0)while(x<0)x=x+b;
    else while(x-b>0)x=x-b;
    printf("%d\n",x);
    return 0;
}

codevs 同余方程

质因数分解

这个吗 一般算法的复杂度是够用的
当然如果筛素数的话会快 而且对于一个质数 可以直接返回
当然如果对n!每个数质因数分解的话那筛素数就快多了
当然我们还有别的方法 忘记叫什么名字了 咨询的数竞的孩子
n!里p的个数(p为素数)=n/p+n/(p*p)+n/(p*p*p)+n/(p*p*p*p)...(p*p*..)<=n
这样就快得多了 有时排列组合可以用到这个

3.

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n;
int a[10000];

int main()
{
    scanf("%d",&n);
    printf("%d=",n);
    int cnt=0;
    for (int i=2;i<=n;i++)
    {
        while (n%i==0&&n)
        {
            a[cnt++]=i;
            n/=i;
        }
    }
    for (int i=0;i<cnt-1;i++)
    {
        printf("%d*",a[i]);
    }
    printf("%d\n",a[cnt-1]);
    return 0;
} 

分解单个数

4.

#include<iostream>
#include<cstdio>
#define maxn 5000010
#define mod 100000007
#define ll long long
using namespace std;
ll n,prime[maxn/10],c[maxn/10],num,ans=1;
bool f[maxn]; 

void Prime()
{
    for(int i=2;i<=n;i++)
    {
        if(f[i]==0)prime[++num]=i;
        for(int j=1;j<=num;j++){
            if(i*prime[j]>maxn-10)break;
            f[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
void Solve(){
    for(int i=1;i<=num;i++){
        ll P=prime[i];
        if(P>n)break;
        while(n>=P){
            c[i]+=n/P;P*=prime[i];
        }
        if(c[i]) printf("%d ",c[i]);
    }
}

int main()
{
    cin>>n;
    Prime();Solve();
    return 0;
}

阶乘分解

快速幂

5.

#include<iostream>
#include<cstdio>
#define mod 1000000007

using namespace std;
int x,y;

int main()
{
    scanf("%d%d",&x,&y);
    int r=1;
    while(y)
    {
        if(y&1) r=(long long)r*x%mod;//y&1 pan duan zhe yi wei shi fou shi yi
        y>>=1;x=(long long)x*x%mod;
    }
    printf("%d",r%mod);
    return 0;
}

快速幂取模

欧拉函数
定义:设n为正整数 不大于n的且与n互素的整数个数记为f(n) 
求欧拉函数的方法
首先暴力好打 慢
f(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)... pi为n的质因子 
那就要分解质因数了 好办
应用嘛 还是比较好使的
求逆元
定义应用
a^(f(p))%p=1

6.

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
ll n,ans;
ll init()
{
    ll x=0;char s=getchar();
    while(s<‘0‘||s>‘9‘)s=getchar();
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x;
}
int main()
{
    while(1)
      {
          n=init();
          if(n==0)break;
          ans=n;
        for(ll i=2;i*i<=n;i++)
          if(n%i==0)
              {
                while(n%i==0)n/=i;
                ans=ans/i*(i-1);
            }
        if(n>1)ans=ans/n*(n-1);
        printf("%ld\n",ans);
      }
    return 0;
}

欧拉函数

素数

7.

#include<cstdio>
#define maxn 22000
using namespace std;
int l,r,cnt,num,prime[maxn];
bool f[maxn];
void Oprime(){
    for(int i=2;i<=maxn;i++){
        if(f[i]==0)prime[++num]=i;
        for(int j=1;j<=num;j++){
            if(i*prime[j]>maxn)break;
            f[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
int main()
{
    scanf("%d%d",&l,&r);
    Oprime();
    for(int i=1;i<=num;i++){
        if(prime[i]>=l&&prime[i]<=r)cnt++;
        if(prime[i]>r)break;
    }
    printf("%d\n",cnt);
    return 0;
}

欧拉筛

素数判定

(1)费马小定理

复杂度(次数*logn) 
若p为素数 则a^(p-1)%p=1
但是如果翻过来就不一定正确
优异类数叫做卡迈克尔数就是合数
但上面那个概率是很大的所以嘛
多生成几个a试试 一般出错的概率还是很小的
当然如果考试那天人品XX的话就怨不得谁了

8.

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#define ll long long

using namespace std;
ll p,flag;

ll mul(ll a,ll b)
{
    a%=p;b%=p;
    ll r=0;
    while(b)
    {
        if(b&1)
        {
            b--;r+=a;r%=p;
        }
        a<<=1;a%=p;b>>=1;
    }
    return r%p;
}

ll qm(ll a,ll b)
{
    ll r=1;
    while(b)
    {
        if(b&1) r=mul(r,a);
        b>>=1; a=mul(a,a);
    }
    return r;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>p;
    if(p==1)
    {
        printf("No\n");
        return 0;
    }
    if(p==2)
    {
        printf("Yes\n");
        return 0;
    }
    srand(time(0));
    for(int i=1;i<=15;i++)
    {
        int a=rand()%(p-1)+1;
        int x=qm(a,p-1);
        if(x!=1)
        {
            flag=1;
            break;
        }
    }
    if(flag)
    {
        printf("No");
        return 0;
    }
    else
    {
        printf("Yes");
        return 0;
    }
    return 0;
}

费马小定理

(2)Miller Rabin(摘抄峰峰的,我不会)

复杂度(logn)好像还有个常熟 不过无伤大雅
再说说误判概率 经过k轮这玩意 将合数误判为素数的概率是(1/4)^k
素数误判为合数的概率是0 一般进行个10轮15轮就好了
要是这样的概率都给碰上了那就没啥可说的了....
下面说说算法过程
首先 2特判一下子 对于剩下的奇素数
有 fermat a^(p-1)%p=1
避免出错同时加速这个算法
另一个定理 若x&1,且x*x%p==1 则有x=1或x=-1(即x==p-1)
把p-1写成p-1=m*2^j 然后呢 j次测试 若不满足上面那个东西 直接肯定p不是prime 
每次都乘回来 最后又得到了p-1 再来一次fermat就ok了

9.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#define ll long long
using namespace std;
ll p;
ll mul(ll a,ll b){
    a%=p;b%=p;
    ll r=0;
    while(b){
        if(b&1){
            b--;r+=a;r%=p;
        }
        a<<=1;a%=p;b>>=1;
    }
    return r%p;
}
ll qm(ll a,ll b){
    ll r=1;
    while(b){
        if(b&1)r=mul(r,a);
        b>>=1;a=mul(a,a);
    }
    return r;
}
bool Miller_Rabin(){
    if(p<=2)return 1;
    if(p%2==0)return 0;
    ll x,y,m,k=0,T=15,a;
    m=p-1;
    while(m%2==0){
        k++;m>>=1;
    }
    while(T--){
        a=rand()%(p-1)+1;
        x=qm(a,m);
        for(ll i=1;i<=k;i++){
            y=mul(x,x);
            if(y==1&&x!=1&&x!=p-1)return 0;
            x=y;
        }
        if(x!=1)return 0;
    }
    return 1;
}
int main()
{
    cin>>p;
    if(Miller_Rabin())printf("Yes\n");
    else printf("No\n");
    return 0;
}

Miller Rabin

表示还很弱很弱很弱,不会的还有很多很多很多.......

时间: 2024-10-06 22:41:53

数论基础模板的相关文章

数论基础的补充讲解

数论基础的补充讲解 整除的一些性质: (1)能被2整除的数,个位上的数都能被2整除 (2*)能被4整除的数,个位和十位所组成的两位数能被4整除 (3*)能被8整除的数,百位.十位和个位所组成的三位数能被8整除 (4)能被5整除的数,末尾是0或5 (5*)能被25整除的数,十位和个位所组成的两位数能被25整除 (6*)能被125整除的数,百位.十位和个位所组成的三位数能被125整除 (7)能被3整除的数,各个数位上的数字之和能被3整除 (8*)能被9整除的数,各个数位上的数字和能被 9 整除 (9

数论基础的补充解说

数论基础的补充解说 整除的一些性质: (1)能被2整除的数,个位上的数都能被2整除 (2*)能被4整除的数,个位和十位所组成的两位数能被4整除 (3*)能被8整除的数,百位.十位和个位所组成的三位数能被8整除 (4)能被5整除的数.末尾是0或5 (5*)能被25整除的数.十位和个位所组成的两位数能被25整除 (6*)能被125整除的数.百位.十位和个位所组成的三位数能被125整除 (7)能被3整除的数,各个数位上的数字之和能被3整除 (8*)能被9整除的数.各个数位上的数字和能被 9 整除 (9

【转】手摸手,带你用vue撸后台 系列四(vueAdmin 一个极简的后台基础模板)

前言 做这个 vueAdmin-template 的主要原因是: vue-element-admin 这个项目的初衷是一个vue的管理后台集成方案,把平时用到的一些组件或者经验分享给大家,同时它也在不断的维护和拓展中,比如最近重构了dashboard,加入了全屏功能,新增了tabs-view等等.所以项目会越来越复杂,不太适合很多初用vue的同学来构建后台.所以就写了这个基础模板,它没有复杂的功能,只包含了一个后台需要最基础的东西.vueAdmin-template 主要是基于vue-cli w

数论基础题目八题【欧几里得】【筛法素数】【中国剩余定理】

之前看的数论的知识,现在做几道题目找找感觉..... poj 1061 传送门 题目大意,给你x,y,m,n,L.代表青蛙a的坐标x,青蛙b的坐标y,青蛙a一次跳的距离m,青蛙b一次跳的距离n,以及mod的值L,求经过多少次跳相遇.即求:(m-n)*x0=(x-y)(mod L);  模线性方程的解,不过要注意处理,因为(m-n)和(x-y)有可能是负的,如果(m-n)是负的,则直接对俩数取负数,下面就是对 ((x-y)+L)%L. 然后就能用modular_linear_equation(LL

UVA11178 Morley&#39;s Theorem(基础模板)

题目链接 题意:给出A,B, C点坐标求D,E,F坐标,其中每个角都被均等分成三份   求出 ABC的角a, 由 BC 逆时针旋转 a/3 得到BD,然后 求出 ACB 的角a2, 然后 由 BC顺时针 旋转 a2 / 3得到 DC,然后就交点 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath&g

树状数组(二叉索引树 BIT Fenwick树) *【一维基础模板】(查询区间和+修改更新)

刘汝佳:<训练指南>Page(194) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; //一维树状数组基础模板 int lowbit(int x) { return x&(-x); } int c[1001]; int sum(int x) //计算从1到x的数组元素的和 { int

「数论基础」欧拉定理(费马小定理)

在阅读本篇之前,如果还不熟悉欧拉函数,可以参见另一篇介绍欧拉函数的「数论基础」欧拉函数. 定义:对于互质的两个正整数$a, n$,满足$a^{φ(n)} ≡ 1\  (mod\ n)$ 证明: 设集合$S$包含所有$n$以内与$n$互质的数,共有$φ(n)$个:     $S = \{ x_1, x_2, ..., x_{φ(n)} \} $ 再设集合$T$: $T = \{ a * x_1 \% n, a * x_2 \% n, ..., a * x_{φ(n)} \% n \} $ 由于$

你也可以手绘二维码(二)纠错码字算法:数论基础及伽罗瓦域GF(2^8)

摘要:本文讲解二维码纠错码字生成使用到的数学数论基础知识,伽罗瓦域(Galois Field)GF(2^8),这是手绘二维码填格子理论基础,不想深究可以直接跳过.同时数论基础也是Hash算法,RSA算法等密码学的入门基础. 二维码生成算法最为核心的就是编码规则和纠错码字的生成.本篇专门讲解纠错涉及到的伽罗瓦域(Galois Field).本文内容大部分是阅读<密码编码学与网络安全>后参考相关PPT编写,如有遗漏或不严谨地方请参考专业书籍. 数论基础 整除,因数,素数 设 a , b(b≠0)

数论基础学习总结(持续补充中)

数论基础 算术基本定理(唯一分解定理) 任何一个大于1的自然数都可以唯一分解成有限个素数的乘积 $N=p_1^{a_1}\times p_2^{a_2}\times...\times p_n^{a_n} | p_1<p_2<...<p_n ,a_i\in Z$ 上式中$p_i$为素数 有关素数筛 埃式筛法 就是拿一个已经筛选出的素数去排掉其他的数,比如2是素数,就用他筛掉2*2,2*3,2*4……,3是素数,就用他筛掉3*2,3*3,3*4……,把每个素数的倍数都筛掉,不过我们发现,3*