ACM数论模板及应用

引论

      数论是算法竞赛的宠儿,几乎每个算法竞赛(不论是ACM的省赛、区域赛还是牛客网上的网络赛)都会出一道关于数论的题。这很容易理解,因为算法与数学的关系极其密切,也可以说算法拼到最后就是在拼数学,所以学好数学对于我们来说是至关重要的。下面我将给出数论的基本模板并附上相关的习题及AC代码

模板

#include<stdio.h>
#include<math.h>
#include<string.h>

typedef long long LL;

const int maxn = 10000000 + 10;
const int maxp = 700000;

int vis[maxn];     //用于在埃氏筛法中判断是否访问过
int prime[maxp];    //用于存储素数

int fac[1000005];   //存储一个整数的素因子
int cnt = 0;     //记录有多少素因子

//因数分解
void factor(int n)
{
    int a = 1;
    for(int i=2; i*i<=n; i+=a,a=2)
    {
        if(n%i==0) while(n%i==0)
        {
            fac[cnt++] = i;
            n /= i;
        }
    }
    if(n > 1) fac[cnt++] = n;
}


//素性测试,用于判断单个数字是否是素数
int is_prime(LL n)
{
    if(n <= 1) return 0;
    LL m = floor(sqrt(n) + 0.5);
    for(LL i = 2; i <= m; i++)
        if(n % i == 0) return 0;
    return 1;
}


//筛选素数
void sieve(int n)
{
    int m = (int)sqrt(n + 0.5);
    memset(vis,0,sizeof(vis));
    for(int i = 2; i <= m; i++)
        for(int j = i * i; j <= n; j += i)
            vis[j] = 1;
}


//生成素数表,放在prime数组中,返回素数个数
int gen_primes(int n)
{
    sieve(n);
    int c = 0;
    for(int i = 2; i <= n; i++) if(!vis[i])
        prime[c++] = i;
    return c;
}


//欧几里得算法(又名辗转相除法)
LL gcd(LL a, LL b)
{
    return b == 0 ? a : gcd(b, a % b);
}


//扩展欧几里得算法
void gcdEx(LL a, LL b, LL &d, LL &x, LL &y)
{
    if(!b) { d = a; x = 1; y = 0; }
    else { gcdEx(b, a % b, d, y, x); y -= x * (a / b); }
}


//模运算
LL mul_mod(LL a, LL b, LL n)
{
    return a * b % n;
}


//快速幂+模运算
LL pow_mod(LL a, LL p, LL n)
{
    if(p == 0) return 1;
    if(p == 1) return a % n;


    LL ans = pow_mod(a, p / 2, n);
    ans = ans * ans % n;
    if(p & 1) ans = ans * a % n;
    return ans;
}


//计算单个欧拉函数
int euler_phi(int n)
{
    int m = (int)sqrt(n + 0.5);
    int ans = n;
    for(int i = 2; i <= m; i++)
        if(n % i == 0){
            ans = ans / i * (i - 1);
            while(n % i == 0) n /= i;
        }
    if(n > 1) ans = ans / n * (n - 1);
    return ans;
}


//欧拉函数表
int phi[maxn];
void phi_table(int n)
{
    for(int i = 2; i <= n; i++) phi[i] = 0;
    phi[1] = 1;
    for(int i = 2; i <= n; i++)
        for(int j = i; j <= n; j += i){
            if(!phi[j]) phi[j] = j;
            phi[j] = phi[j] / i * (i - 1);
        }
}


//计算模n下a的逆
LL inv(LL a, LL n)
{
    LL d, x, y;
    gcdEx(a,n,d,x,y);
    return d == 1 ? (x + n) % n : -1;
}

应用

快速幂+模运算

hdu1061 hdu3003  hdu1163 hdu5690

欧拉函数

hdu1286   

素数

hdu2012 51nod1181 hdu2161

逆元

zoj3609

欧几里得算法及扩展欧几里得算法

uva11827 hdu2669  poj1061

 

习题代码

由于习题过多,在这里我不贴出我的代码,想看代码的同学可以参考我的github

 

几何\ 多边形 多边形切割 浮点函数 几何公式 面积 球面 三角形 三维几何 凸包(graham) 网格(pick) 圆 整数函数 注意 结构\ 并查集 并查集扩展(friend_enemy) 堆(binary) 堆(mapped) 矩形切割 线段树 线段树扩展 线段树应用 子段和 子阵和 其他\ 大数(整数类封装) 分数 矩阵 线性方程组(gauss) 日期 线性相关 数论\ 阶乘最后非零位 模线性方程(组) 质数表 质数随机判定(miller_rabin) 质因数分解 最大公约数欧拉函数 数值计算\ 定积分计算(Romberg) 多项式求根(牛顿法) 周期性方程(追赶法) 图论_NP搜索\ 最大团(n小于64) 最大团 图论_连通性\ 无向图关键边(dfs邻接阵形式) 无向图关键点(dfs邻接阵形式) 无向图块(bfs邻接阵形式) 无向图连通分支(bfs邻接阵形式) 无向图连通分支(dfs邻接阵形式) 有向图强连通分支(bfs邻接阵形式) 有向图强连通分支(dfs邻接阵形式) 有向图最小点基(邻接阵形式) 图论_匹配\ 二分图最大匹配(hungary邻接表形式) 二分图最大匹配(hungary邻接阵形式) 二分图最大匹配(hungary邻接表形式,邻接阵接口) 二分图最大匹配(hungary正向表形式) 二分图最佳匹配(kuhn_munkras邻接阵形式) 一般图最大匹配(邻接表形式) 一般图最大匹配(邻接阵形式) 一般图最大匹配(正向表形式) 一般图匹配(邻接表形式,邻接阵接口) 图论_网络流\ 上下界最大流(邻接阵形式) 上下界最小流(邻接阵形式) 上下界最大流(邻接表形式) 上下界最小流(邻接表形式) 最大流(邻接阵形式) 最大流(邻接表形式) 最大流(邻接表形式,邻接阵接口) 最大流无流量(邻接阵形式) 最小费用最大流(邻接阵形式) 图论_应用\ 欧拉回路(邻接阵形式) 前序表转化 树的优化算法 拓扑排序(邻接阵形式) 最佳边割集 最佳顶点割集 最小边割集 最小顶点割集 最小路径覆盖 图论_最短路径\ 最短路径(单源bellman_ford邻接阵形式) 最短路径(单源dijkstra邻接阵形式) 最短路径(单源dijkstra_bfs邻接表形式) 最短路径(单源dijkstra_bfs正向表形式) 最短路径(单源dijkstra+binary_heap邻接表形式) 最短路径(单源dijkstra+binary_heap正向表形式) 最短路径(单源dijkstra+mapped_heap邻接表形式) 最短路径(单源dijkstra+mapped_heap正向表形式) 最短路径(多源floyd_warshall邻接阵形式) 图论_支撑树\ 最小生成树(kruskal邻接表形式) 最小生成树(kruskal正向表形式) 最小生成树(prim邻接阵形式) 最小生成树(prim+binary_heap邻接表形式) 最小生成树(prim+binary_heap正向表形式) 最小生成树(prim+mapped_heap邻接表形式) 最小生成树(prim+mapped_heap正向表形式) 最小树形图(邻接阵形式) 应用\ joseph模拟 N皇后构造解 布尔母函数 第k元素 幻方构造 模式匹配(kmp) 逆序对数 字符串最小表示 最长公共单调子序列 最长子序列 最大子串匹配 最大子段和 最大子阵和 组合\ 排列组合生成 生成gray码 置换(polya) 字典序全排列 字典序组合 组合公式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值