acm模板

这篇博客详细介绍了ACM竞赛中常用的算法模板,包括欧拉筛法、快速幂、矩阵快速幂、扩展欧几里得算法。同时,探讨了一维和二维完全背包问题的解决策略,以及01背包问题的从后往前解法。此外,还涵盖了树状数组和大数运算等核心概念,是ACMer必备的知识点。
摘要由CSDN通过智能技术生成

持续补充。。。

vim配置

syntax on
set cindent
set nu
set tabstop=4
set shiftwidth=4
set background=dark

map <C-A> ggVG"+y
map <F5> :call Run()<CR>
func! Run()
	exec "w"
	exec "!g++ -Wall % -o %<"
	exec "!./%<"
endfunc
欧拉筛法
/*求小于等于n的素数的个数*/
#include<stdio.h>
#include<string.h>
using namespace std;
int main()
{
    int n, cnt = 0;
    int prime[100001];//存素数 
    bool vis[100001];//保证不做素数的倍数 
    scanf("%d", &n);
    memset(vis, false, sizeof(vis));//初始化 
    memset(prime, 0, sizeof(prime));
    for(int i = 2; i <= n; i++)
    {
        if(!vis[i])//不是目前找到的素数的倍数 
        prime[cnt++] = i;//找到素数~ 
        for(int j = 0; j<cnt && i*prime[j]<=n; j++)
        {
            vis[i*prime[j]] = true;//找到的素数的倍数不访问 
            if(i % prime[j] == 0) break;//关键!!!! 
        }
    }
    printf("%d\n", cnt);
    return 0;
}
快速幂
LL quick_pow(LL a,LL b)
{
    LL res = 1;
    while(b)
    {
        if(b%2 != 0) res *= a;
        a *= a;
        b /= 2;
    }
    return res;
}
矩阵快速幂
#include <stdio.h>
#include <cstring.>
typedef struct Matrix
{
    int m[3][3];
}Matrix;
Matrix multiple(Matrix a,Matrix b,int n)
{
    Matrix res;
    memset(&res,0,sizeof(res));//初始化
    for(int i = 0;i<n;i++)
        for(int j = 0;j<n;j++)
            for(int k = 0;k<n;k++)
                res.m[i][j] += a.m[i][k]*b.m[k][j];
    return res;
    
}
Matrix quick_pow(Matrix a,int N,int n)//N表示求a的几次幂,n表示阶数
{
    Matrix res;
    //初始化为单位矩阵
    for(int i = 0;i<n;i++)
        for(int j = 0;j<n;j++)
            if(i == j) res.m[i][j] = 1;
            else res.m[i][j] = 0;
    while(N)
    {
        if(N&1)
            res = multiple(res,a,n);
            a = multiple(a,a,n);
        N = N>>1;
    }
    return res;
}
扩展欧几里得
/*
ax+by = gcd(a,b)
a,b是系数, d 是gcd(a,b),x,y是一组解
*/
void gcd(int a,int  b,int &d,int &x,int &y)
{
    if(!b){
        d = a;
        x = 1;
        y = 0;
    }else{
        gcd(b,a%b,d,y,x);
        y -= x *(a/b);
    }
}
一维完全背包(从前往后)
    for(i = 0;i<n;i++)
    			{
    				int j = m;
    				for(j = w[i];j<=m;j++)
    				{
    					dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
    				}	
    			}	

二维维完全背包(从前往后)
for(i = 0;i<k;i++)
			for(j = 1;j<=s;j++)
				for(l = w[i];l<=m;l++)
				{
					dp[j][l] = max(dp[j][l],dp[j-1][l-w[i]]+v[i]);
				}
01背包(从后往前)
    for(i = 0;i<n;i++)
    		{
    			for(j = s;j>=c[i];j--)
    			{
    				dp[j] = max(dp[j],dp[j-c[i]]+v[i]);
    			}
    		}
树状数组
    求i二进制最低位的权重
    int lowbit(int i)
    {
    return i&(-i);
    }
    
    维护前缀和数组
    void add(int x,int num)//x节点加num
    {
    while(x <= Max)
    {
    c[x] += num;
    x += lowbit(x);
    }
    return ;
    }
    求前x项和:
    int sum(int x)
    {
    int sum = 0;
    while(x)
    {
    sum += c[x];
    x -= lowbit(x);
    }
    return sum;
    }

大数运算

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

const int MAXN=1e5;
const int siz=8;
const long long MOD=1e8;//1e siz压位需要取的模数

char ch1[MAXN],ch2[MAXN];
bool f1,f2,f;
long long n;
long long a[MAXN>>2],b[MAXN>>2],s[MAXN>>2];
long long cp[MAXN>>2],lt[MAXN>>2],wsd[MAXN>>2];

void write(long long num[]);//输出函数
void clear(long long num[]);//重置函数
void ry(long long num[]);//>>二进制右移
void ly(long long num[]);//<<二进制左移
void cpy(long long num1[],long long num2[]);//复制函数
int cmp(long long num1[],long long num2[]);//比较函数
void pls(long long a[],long long b[]);//plus加法运算
void mnu(long long a[],long long b[]);//minus减法运算
void mul(long long a[],long long b[]);//multiply乘法运算
void div(long long a[],long long b[]);//divided除法运算

void write(long long num[])
{
    if(f) putchar('-'),f=0;
    printf("%lld",num[num[0]]);
    for(int i=num[0]-1;i;--i) printf("%08lld",num[i]);
    puts("");
}

void clear(long long num[])
{
    for(int i=num[0];i;--i) num[i]=0;
    num[0]=1;
}

void ry(long long num[])
{
    for(int i=num[0];i;--i){
        if((num[i]&1)&&i>1) num[i-1]+=MOD;
        num[i]>>=1;
    }if(!num[num[0]]&&num[0]>1) --num[0];
}

void ly(long long num[])
{
    ++num[0];
    for(int i=1;i<=num[0];++i){
        num[i]<<=1;
        if(num[i-1]>=MOD) num[i-1]-=MOD,++num[i];
    }if(!num[num[0]]&&num[0]>1) --num[0];
    return;
}

void cpy(long long num1[],long long num2[])
{
    for(int i=num1[0];i>num2[0];--i) num1[i]=0;
    for(int i=0;i<=num2[0];++i) num1[i]=num2[i];
}

int cmp(long long num1[],long long num2[])
{
    if(num1[0]>num2[0]) return 1;
    if(num1[0]<num2[0]) return -1;
    for(int i=num1[0];i;--i){
        if(num1[i]>num2[i]) return 1;
        if(num1[i]<num2[i]) return -1;
    }return 0;
}

void init()
{
    scanf("%s%s",ch1,ch2);
    if(ch1[0]=='-') ch1[0]='0',f1=1;
    if(ch2[0]=='-') ch2[0]='0',f2=1;//对符号的处理
    int l1=strlen(ch1),l2=strlen(ch2);
    for(int i=l1-1;i>=0;i-=siz){
        long long pw=1;++a[0];
        for(int j=i;j>i-siz&&j>=0;--j){
            a[a[0]]+=(ch1[j]^48)*pw;
            pw=(pw<<3)+(pw<<1);
        }
    }for(int i=l2-1;i>=0;i-=siz){
        long long pw=1;++b[0];
        for(int j=i;j>i-siz&&j>=0;--j){
            b[b[0]]+=(ch2[j]^48)*pw;
            pw=(pw<<3)+(pw<<1);
        }
    }return;
}

void pls(long long a[],long long b[])
{
    if(f1^f2){
        if(f1) f1^=1,mnu(b,a),f1^=1;
        if(f2) f2^=1,mnu(a,b),f2^=1;//加负数等效于减正数
        return;
    }if(f1&f2){
        f1=f2=0,f^=1,pls(a,b);
        f1=f2=1;return;
    }clear(s);s[0]=max(a[0],b[0])+1;
    for(int i=1;i<=s[0];++i){
        s[i]+=a[i]+b[i];
        if(s[i]>=MOD) s[i]-=MOD,++s[i+1];
    }if(!s[s[0]]&&s[0]>1) --s[0];
    return;
}

void mnu(long long a[],long long b[])
{
    if(f1^f2){
        if(f1) f1^=1,f^=1,pls(a,b),f1^=1;
        if(f2) f2^=1,pls(a,b),f2^=1;//减负数等效于加正数
        return;
    }if(f1&f2){
        f1=f2=0,mnu(b,a);
        f1=f2=1;return;
    }if(cmp(a,b)==-1){
        f^=1;mnu(b,a);return;
    }clear(s);s[0]=max(a[0],b[0]);
    for(int i=1;i<=s[0];++i){
        s[i]+=a[i]-b[i];
        if(s[i]<0) s[i]+=MOD,--s[i+1];
    }while(!s[s[0]]&&s[0]>1) --s[0];
    return;
}

void mul(long long a[],long long b[])//模拟竖式乘法
{
    if(f1^f2) f^=1;
    clear(s);s[0]=a[0]+b[0];
    for(int i=1;i<=a[0];++i){
        for(int j=1;j<=b[0];++j){
            s[i+j-1]+=a[i]*b[j];
            if(s[i+j-1]>=MOD) s[i+j]+=s[i+j-1]/MOD,s[i+j-1]%=MOD;
        }
    }if(!s[s[0]]&&s[0]>1) --s[0];
    return;
}

void div(long long a[],long long b[])
{
    if(f1^f2){
        if(f1) f1^=1,f^=1,div(a,b),f1^=1;
        if(f2) f2^=1,f^=1,div(a,b),f2^=1;
        return;
    }clear(s);
    clear(cp),cp[1]=1;clear(lt);
    while(cmp(a,b)!=-1) ly(b),ly(cp);//这里试探商的二进制最高位
    while(cp[0]>1||cp[1]){
        if(cmp(a,b)!=-1){
            mnu(a,b),cpy(a,s);
            pls(lt,cp),cpy(lt,s);//倍增减法,算法主体
        }ry(b),ry(cp);
    }cpy(s,lt),cpy(lt,a);//s为商,lt为余数
    return;
}

int main()
{
    init();
    clear(s);
//  pls(a,b);write(s);
//  mnu(a,b);write(s);
//  mul(a,b);write(s);
    div(a,b);write(s);//write(lt);
    return 0;
}

二分查找

int lower_bound(int *a,int x,int y,int v)//返回第一个出现的位置,若不存在在此处插入v后仍然有序
//x表示开始查找的开始位置,y表示结束位置即返回值 ∈【x,y】
    while(x < y)//结束循环的条件 左端点>=右端点
    {
        m = x+(y-x)/2;//根据分治思想要尽可能平均分开两部分查找范围
        if(a[m] >= v) y = m;//出现相等元素继续向前找
        else x = m + 1;//针対找过了的情况,像回退一个
    }
    return x;
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An<O(N), O(1)> algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值