蓝桥杯算法模板

蓝桥杯算法模板

2024/4/5:happy:🐉🐲 📓by Michael Zhao 🌉必胜

快速幂

typedef long long LL
    
LL qmi(LL a,LL n,LL q){
	LL res=1%q;
    while(b){
		if(n&1) res=res*a%q;
        a=a*a%q;
        n=n>>1;
    }
    return res;
}

GCD

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

LCM

int lcm(int a,int b){
	return a/gcd(a,b)*b;//除去公因数再乘以倍数
}


int lcm(int a,int b){
    return a/gcd(a,b)*b;
}

全排列

 vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> ret;
        sort(nums.begin(),nums.end());
        do{
            ret.emplace_back(nums);
        }while(next_permutation(nums.begin(),nums.end()));
        return ret;
 }

并查集

int n,m,cnt=0;
int f[10005];
int find(int x){
	if(f[x]==x)return x;
	return f[x]=find(f[x]);
}
void union(int x,int y){
	int a=find(x);
	int b=find(y);
	if(a!=b){
		f[a]=b;
		cnt++;
	}
}

背包

//01背包
#include <iostream>
using namespace std;
int main(){
	int v[MAXN],w[MAXN],dp[MAXN];
	int m,n;//m为总背包大小,n为物品个数
	cin>>m>>n;
	for(int i=1;i<=n;i++){
		cin>>v[i]>>w[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=m;j>=v[i];j--){
			dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
		}
	}
	cout<<dp[m];
}

//完全背包
#include <iostream>
using namespace std;
int main(){
	int v[MAXN],w[MAXN],dp[MAXN];
	int m,n;//m为总背包大小,n为物品个数
	cin>>m>>n;
	for(int i=1;i<=n;i++){
		cin>>v[i]>>w[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=v[i];j<=m;j++){
			dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
		}
	}
	cout<<dp[m];
}

LCS——最长公共子序列

/*
    |求最长公共子序列|
    |递推形式|
*/

void solve() {  
    for (int i = 0; i < n; ++i) {  
        for (int j = 0; j < m; ++j) {  
            if (s1[i] == s2[j]) {  
                dp[i + 1][j + 1] = dp[i][j] + 1;  
            }else {  
                dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);  
            } } }
}  

树状数组

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int maxn = 50005;

int a[maxn];
int n;

int lowbit(const int t) {
    return t & (-t);
}

void insert(int t, int d) {
    while (t <= n){
        a[t] += d;
        t = t + lowbit(t);
    }
}

ll getSum(int t) {
    ll sum = 0;
    while (t > 0){
        sum += a[t];
        t = t - lowbit(t);
    }
    return sum;
}

润年判断

bool isleaf(int x){
	return x%400==0||(x%4==0&&x%100!=0);
}

筛选素数

bool isprime(int n){
	if(n==1)return false;
	for(int i=2;i*i<n;i++){
		if(n%i==0)return false;
	}
	return true;
}

前缀和

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,a[N],b[N];
int main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for (int i=1; i<=n; i++) {
        cin>>a[i];
        b[i]=a[i]+b[i-1];
    }
    for (int i=1; i<=m; i++) {
        int x,y;
        cin>>x>>y;
        cout<<b[y]-b[x-1]<<endl;
    }
    return 0;
}

差分

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int a[N],b[N];
int n,m,l,r,c,x;
int main() {
    cin>>n>>m;
    for (int i=1; i<=n; i++) {
        cin>>a[i];
        b[i]=a[i]-a[i-1];
    }

    while (m--) {
        cin>>l>>r>>c;
        b[l]+=c;
        b[r+1]-=c;
    }
    for (int i=1; i<=n; i++) {
        x+=b[i];
        cout<<x<<" ";
    }
    return 0;
}

二分查找

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,a[N],x,ans;
int main() {
    ios::sync_with_stdio(0);
    cin>>n;
    for (int i=1; i<=n; i++) {
        cin>>a[i];
    }
    cin>>x;
    int l=1,r=n;
    while (l<=r) {
        int mid=(l+r)>>1;
        if (a[mid]==x) {
            ans=mid,r=mid-1;
        } else if (a[mid]<x) {
            l=mid+1;
        } else {
            r=mid-1;
        }
    }
    if (!ans) {
        cout<<-1;
    } else {
        cout<<ans;
    }
    return 0;
}

区间修改,区间查询

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,a[N],b[N],c[N],maxn;
int lowbit(int a) {
    return a&(-a);
}
void update(int x,int y) {
    for (int i=x; i<=n; i+=lowbit(i)) {
        b[i]+=y;
        c[i]+=x*y;
    }
}
void range_update(int l,int r,int x) {
    update(l,x);
    update(r+1,-x);
}
int query(int x) {
    int ans=0;
    for (int i=x; i; i-=lowbit(i)) {
        ans+=(x+1)*b[i]-c[i];
    }
    return ans;
}
int range_query(int l,int r) {
    return query(r)-query(l-1);
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for (int i=1; i<=n; i++) {
        cin>>a[i];
        update(i,a[i]-a[i-1]);
    }
    for (int i=1; i<=m; i++) {
        int q,x,y,k;
        cin>>q;
        if (q==1) {
            cin>>x>>y>>k;
            range_update(x,y,k);
        } else {
            cin>>x>>y;
            cout<<range_query(x,y)<<endl;
        }
    }
    return 0;
}

矩阵乘法

struct matrix {
    int mat[N][N];
    matrix() {
        memset(mat,0,sizeof mat);
    }
    matrix operator*(const matrix& b)const {
        matrix ans;
        for (int i=1; i<=N; i++) {
            for (int j=1; j<=N; j++) {
                for (int k=1; k<=N; k++) {
                    ans.mat[i][j]=(ans.mat[i][j]+mat[i][k]*b.mat[k][j]%MOD)%MOD;
                }
            }
        }
        return ans;
    }
};

KMP

vector<int> getNext(string s){
    int n=s.size();
    vector<int> v(n);
    int i=0,j=-1;
    while(i<n){
        if(j==-1||s[i]==s[j]){
            i++;
            j++;
            v[i]=j;
        }else{
            j=v[j];
        }
    }
}
int kmp(string s1,string s2){
    vector<int> next=getNext(s2);
    int i=0,j=0;
    while(i<s1.size()&&j<s2.size()){
        if(j==-1||s1[i]==s2[j]){
            i++;
            j++;
        }else{
            j=next[j];
        }
    }
    if(j==s2.size()) return i-j;
    else return -1;
}

SPFA

const int inf=1e9;
const int maxn=;
vector<int> to[maxn],weight[maxn];
int dis[maxn];
bool vis[maxn];
int n,start,dest;
void spfa(int start){
    int i,j;
    for(i=0;i<n;i++){
        dis[i]=inf;
        vis[i]=false;
    }
    dis[start]=0;
    vis[start]=true;
    queue<int> Q;
    Q.push(start);
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        vis[u]=false;
        for(i=0;i<to[u].size();i++){
            int v=to[u][i],w=weight[u][i];
            if(dis[u]+w<dis[v]){
                dis[v]=dis[u]+w;
                if(!vis[v]){
                    vis[v]=true;
                    Q.push(v);
                }
            }
        }
    }
}

Vector

size()
empty()
clear()
begin()/end()

lower_bound/upper_bound

这两个二分查找操作可以在set,数组,vector,map中使用;
 
数组 或者 vector 中的语法:
序列是升序的(从小到大)
lower_bound(begin(),end(),x) //返回序列中第一个大于等于x的元素的地址
upper_bound(begin(),end(),x) //返回序列中第一个大于x的元素的地址
 
序列是降序的(从大到小)
lower_bound(begin(),end(),x,greater<tpye>()) //返回序列中第一个小于等于x的元素的地址
upper_bound(begin(),end(),x,greater<type>()) //返回序列中第一个小于x的元素的地址
 
 
set 或者 map 中的语法:
和数组差不多,只不过返回的是迭代器:
s.lower_bound(x) //返回序列中第一个大于等于x的元素的地址
s.upper_bound(x) //返回序列中第一个大于x的元素的地址
 
 
重点注意:如果当前序列中找不到符合条件的元素,那么返回end(),对于数组来说,返回查询区间的尾地址位置,对于set来讲,返回end()-1后面元素的迭代器,也就是end();

set

set/multiset
前者去重后者不去重
 
intsert() 插入一个数
 
find() 查找一个数
 
count() 返回一个数的个数
 
erase()
   (1) 输入是一个数x,删除所有x   O(k + logn)
   (2) 输入一个迭代器,删除这个迭代器

map

map/multimap 
(它们都是关联容器,增删效率为log级别,并且依据key能自动排序,默认小于,前者key不允许重复,后者允许)
    insert()  插入的数是一个pair
    erase()  输入的参数是pair或者迭代器
    find()
    []  注意multimap不支持此操作。 时间复杂度是 O(logn)
    lower_bound()/upper_bound()

string

string  是一个很强大的字符串类
 
size()/length()  返回字符串的长度
 
reverse(s.begin(),s.end());    将字符串的反转
 
s.append(str)  在字符串后面加上字符串str
支持对两个字符串的 ’ + ‘ 操作,实现字符串的拼接(s.append(str)比 + 要慢)
 
s.erase(0,s.find_first_not_of('0'));  //利用string函数去除前导0
 
s1=s2.substr(起始下标,拷贝长度)    //string的截取
 
pos = s.find('x')  //返回string里面字符x的下标;
 
字符串转化为数字的库函数:
string str = "16";
int a = atoi(str.c_str());//能转换整数和小数,能报异常
int b = strtol(str.c_str(), nullptr, 10);//能指定进制
 
数字转化为字符串的函数:
int val=123456;
string s=to_string(val);
 
iterator erase(iterator p):删除字符串中p所指的字符
iterator erase(iterator first, iterator last):删除字符串中迭代器区间 [first, last) 上所有字符
string& erase(size_t pos, size_t len):删除字符串中从索引位置 pos 开始的 len 个字符

Iterator

vector<type>::iterator iter;
map<type,type>::iterator iter;
set<type>::iterator iter;
等等.....
 
迭代器可以像指针一样,遍历STL时可以直接对迭代器 ++ --  ;
访问迭代器的值的形式:
*iter
iter->first    iter->second   

双指针

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;
 
    // 具体问题的逻辑
}
常见问题分类:
    (1) 对于一个序列,用两个指针维护一段区间
    (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

倍增LCA

void bfs(int root)//从根节点开始处理每个点的深度并且进行fa的倍增
{
    memset(depth,0x3f,sizeof depth);
    queue<int> q;
    q.push(root);
    depth[0]=0,depth[root]=1;//设置哨兵
    while(q.size())
    {
        int t=q.front();
        q.pop();
        for(int i=h[t];~i;i=ne[i])
        {
            int j=e[i];
            if(depth[j]>depth[t]+1)
            {
                depth[j]=depth[t]+1;
                fa[j][0]=t;
                q.push(j);
                for(int k=1;k<16;k++)//倍增里面的常数根据题目节点个数而定
                    fa[j][k]=fa[fa[j][k-1]][k-1];
            }
        }
    }
}
int lca(int a,int b)
{
    if(depth[a]<depth[b]) swap(a,b);//对深度大的点进行往上跳跃
    for(int k=15;k>=0;k--)
        if(depth[fa[a][k]]>=depth[b]) 
            a=fa[a][k];
    if(a==b) return a;
    for(int k=15;k>=0;k--)//两个点同时跳跃,直到最近公共祖先的下面的节点
    {
        if(fa[a][k]!=fa[b][k])
        {
            a=fa[a][k];
            b=fa[b][k];
        }
    }
    return fa[a][0];//返回a的父亲,也就是最近公共祖先
}

匈牙利算法

nt n1, n2;     // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N], e[M], ne[M], idx;     // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N];       // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N];     // 表示第二个集合中的每个点是否已经被遍历过
 
bool find(int x)
{
    for (int i = h[x]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!st[j])
        {
            st[j] = true;
            if (match[j] == 0 || find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }
 
    return false;
}
 
// 求最大匹配数,依次枚举第一个集合中的每个点能否匹配第二个集合中的点
int res = 0;
for (int i = 1; i <= n1; i ++ )
{
    memset(st, false, sizeof st);
    if (find(i)) res ++ ;
}

字符串哈希

核心思想:将字符串看成P进制数,P的经验值是131或13331,取这两个值的冲突概率低
小技巧:取模的数用2^64,这样直接用unsigned long long存储,溢出的结果就是取模的结果
 
typedef unsigned long long ULL;
ULL h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64
 
// 初始化
p[0] = 1;
for (int i = 1; i <= n; i ++ )
{
    h[i] = h[i - 1] * P + str[i];
    p[i] = p[i - 1] * P;
}
 
// 计算子串 str[l ~ r] 的哈希值
ULL get(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}

DP 最长公共子序列

int main()
{
    int n,m;
    cin >>n>>m;
    for(int i=1;i<=n;i++) cin >>a[i];
    for(int i=1;i<=m;i++) cin >>b[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=max(f[i-1][j],f[i][j-1]);
            if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
        }
    }
    cout <<f[n][m]<<endl;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值