【持续更新】算法竞赛常用模板

一、动态规划

1. 经典01背包

问题: 求背包容量允许范围下,装不同物品(每种物品只可取一次)可得到的最高价值

for(int i=1;i<=n;i++)
	for(int j=v;j>=c[i];j--)
		dp[j]=max(dp[j],dp[j-c[i]]+w[i]);

2. 经典完全背包

问题: 求背包容量允许范围下,装不同物品(每种物品可取无限次)可得到的最高价值

for(int i=1;i<=n;i++)
	for(int j=c[i];j<=v;j--)//必须正序
		dp[j]=max(dp[j],dp[j-c[i]]+w[i]);

二、数学

1. 快速幂

\(x\)是底数,\(n\)是指数,\(p\)为取模数
①普通快速幂

long long qpow(long long x,long long n,long long p){
	if(!n)return 1;
	long long ans=qpow((x%p)*(x%p)%p,n/2,p)%p;
	if(n%2)ans=ans*(x%p)%p;
	return ans;
}

②矩阵快速幂

三、图论

1. 图的存储:

①邻接矩阵存边:略
②邻接表(vector实现)存边:

//定义
struct node{
	int to;//边通向的点的编号
	int val;//边权
}tmp;
vector<node>edge[MAXN];//MAXN是最大点数
//加边
cin>>bh>>tmp.to>>tmp.val;//读入边的起点、终点以及边权
edge[bh].push(tmp);//给以bh号为起点的边,加一条
//遍历
for(int i=0;i<n;i++){
	int len=edge[i].size();
	for(int j=0;j<len;j++)
		……
}

③静态链表头插法存边(链式前向星):

//定义:
struct node {
    int to,val;//数据域.存储边指向的节点以及边权.
    int nxt;//指针域.假如目前这条边的起点为x,那么nxt则模拟了指针,保存下一个起点同样为x的边的编号
} edge[MAXM];
int bh=0;//初始化编号
memset(head,-1,sizeof(head));//初始化head数组,用-1模拟NULL
void add(int from,int to,int val) {//加边函数
    edge[++bh].to=to;    //存储边的数据
    edge[bh].val=val;
    edge[bh].nxt=head[from];    //头插法
    head[from]=bh;
}
for(int i=head[now]; i!=-1; i=edge[i].nxt){//遍历以now为起点的所有边
    int j=edge[i].to;
	……
}

2. 最短路

3. 拓扑排序

4.

四、数据结构

1. 并查集:

2. 最小生成树:

3. 树状数组:

基本功能:单点增减(无法将元素修改为某值,这需要线段树来干)、区间求和.
时间复杂度:\(O_{(nlogn)}\),常数快于线段树
①单点增减、区间求和:单点增减直接调用updade函数,区间求和则是sum(right)-sum(left-1)

//计算lowbit函数
int lowbit(int x) {
    return x&-x;
}
//单点增减
void update(int val,int bh) {
    int i=bh;
    while(i<=n) {
        c[i]+=val;
        i+=lowbit(i);
    }
}
//区间求和
int sum(int i) {
    int tot=0;
    while(i>0) {
        tot+=c[i];
        i-=lowbit(i);
    }
    return tot;
}

②区间增减、单点求值:树状数组本身与上面一样,只不过建树的时候更新的是差分数组,进行区间增减的时候,update(left,val)以及update(right+1,-val),求和的时候只需求差分数组的前缀和sum(x)
③区间增减、区间求和:

4. ST表:

5. 线段树:

6.

五、杂项

1.对拍器:

#include<iostream>
#include<windows.h>
using namespace std;
int main() {
    int t=100;
    while(t) {
        t--;
        system("data.exe > data.txt");
        system("ac1.exe < data.txt > ac1.txt");
        system("t.exe < data.txt > t.txt");
        if(system("fc t.txt ac1.txt"))   break;
    }
    if(t==0) cout<<"no error"<<endl;
    else cout<<"error"<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/yige2019/p/15806272.html