C++算法模板

01背包

//朴素算法
const int N = 1010;
int dp[N][N];
int v[N],w[N];
int n,m; //物品数量  和  背包体积

int main(){
    cin >> n >> m;
    
    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
    
    
    for(int i = 1 ; i <= n ; i++){
        for (int j = 1; j <= m; j ++ ){
            if(j < v[i])
                dp[i][j] = dp[i-1][j];
            else{
                dp[i][j] = max(dp[i-1][j-v[i]] + w[i],dp[i-1][j]);
            }
        }
    }
    cout<<dp[n][m];
    
    return 0;
}
//优化算法(一维)
const int N = 1010;
int n,m; // m为背包容量
int f[N],v[N],w[N];

int main()
{
    cin >> n >> m;
    
    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--){
            f[j] = max(f[j],f[j-v[i]] + w[i]);
        }
    }
    cout<<f[m];
    
    return 0;
}

完全背包

//二维背包
const int N = 1010;
int n,m; // m为背包容量
int f[N][N],v[N],w[N];

int main()
{
    cin >> n >> m;
    
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    
    for (int i = 1 ; i <= n ; i++){
        for (int j = 0; j <= m; j ++ ){
            f[i][j] = f[i-1][j];
            if(j >= v[i])
                f[i][j] = max(f[i][j],f[i][j-v[i]] + w[i]);
        }
    }
    
    cout<<f[n][m];
    
    return 0;
}
//优化算法(一维)
const int N = 1010;
int n,m; // m为背包容量
int f[N],v[N],w[N];

int main()
{
    cin >> n >> m;
    
    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++){
            f[j] = max(f[j],f[j-v[i]] + w[i]);
        }
    }
    cout<<f[m];
    
    return 0;
}

并查集

int find(int x) {  // 并查集
    if (fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}

快速幂

ll qpow(ll a, int b){ //需要取模时记得模p
    ll res = 1;
    while(b){
        if(b & 1) res = res * a;
        b >>= 1;
        a = a * a;
    }
    return res;
}

费马小定理

(a / b) % p == (a * b^(p - 2)) % p

ll qmi(ll a,ll b,ll c) {
	ll ans=1;
	a %= c;
	while(b){
		if(b&1) ans=ans*a%c;
		a=a*a%c;
		b>>=1;
	}	
	return ans%c;
}

ll divi(ll a,ll b,ll p){
	b=qmi(b,p-2,p);	//b的逆元
	return a*b%p; 
}

二分查找

int l = 0 , r = n + 1;
while(l < r){
    int mid = (l + r + 1) / 2; //有加
    if(check(mid)) l = mid;
    else r = mid - 1; //必有减
}

前缀和

while(n--){
	int l,r;
	cin >> l >> r;
	cout << s[r] - s[l - 1] << endl;
}

埃氏筛

/*
    埃式筛
*/

int prime[maxn];  
bool is_prime[maxn];

int sieve(int n){
    int p = 0;
    for(int i = 0; i <= n; ++i)
        is_prime[i] = true;
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i <= n; ++i){
        if(is_prime[i]){
            prime[p++] = i;
            for(int j = i + i; j <= n; j += i)
                is_prime[j] = false;
        }
    }
    return p;   //返回素数个数
}

for (int i = 0; i < cnt; i ++){
    int p = prime[i];
    int s = 0, t = n;
    while(t) s += t / p , t /= p; //求出质因子p的次数是多少
    cout<<p<<" "<<s<<endl;
}

最大公约数、最小公倍数

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

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

Dijkstra--迪杰斯特拉算法

/*
    Dijkstra算法
*/

struct node {  
    int v, len;  
    node(int v = 0, int len = 0) :v(v), len(len) {}  
    bool operator < (const node &a)const {  //  距离从小到大排序  
        return len > a.len;  
    }  
};  

vector<node>G[maxn];  
bool vis[maxn];  
int dis[maxn];

void init() {  
    for (int i = 0; i<maxn; i++) {  
        G[i].clear();  
        vis[i] = false;  
        dis[i] = INF;  
    }  
}  
int dijkstra(int s, int e) {  
    priority_queue<node>Q;  
    Q.push(node(s, 0)); //  加入队列并排序  
    dis[s] = 0;  
    while (!Q.empty()) {  
        node now = Q.top();     //  取出当前最小的  
        Q.pop();  
        int v = now.v;  
        if (vis[v]) continue;   //  如果标记过了, 直接continue  
        vis[v] = true;  
        for (int i = 0; i<G[v].size(); i++) {   //  更新  
            int v2 = G[v][i].v;  
            int len = G[v][i].len;  
            if (!vis[v2] && dis[v2] > dis[v] + len) {  
                dis[v2] = dis[v] + len;  
                Q.push(node(v2, dis[v2]));  
            }  
        }  
    }  
    return dis[e];  
}  

LIS--最长上升子序列

/*
    |最长上升子序列|
*/

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

/* 
    优化方法:
    dp[i]表示长度为i+1的上升子序列的最末尾元素  
    找到第一个比dp末尾大的来代替 
*/
void solve() {  
    for (int i = 0; i < n; ++i){
        dp[i] = INF;
    }
    for (int i = 0; i < n; ++i) {  
       *lower_bound(dp, dp + n, a[i]) = a[i];  //  返回一个指针  
    }  
    printf("%d\n", *lower_bound(dp, dp + n, INF) - dp;  
}

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]);  
            } 
        } 
    }
}  

kmp--克努特-莫里斯-普拉特操作

/*
    kmp算法
*/

void getnext(char str[N], int nextt[N]) {
    int j = 0, k = -1;
    nextt[0] = -1;
    while (j < m) {
        if (k == -1 || str[j] == str[k]) {
            j++;
            k++;
            nextt[j] = k;
        }
        else
            k = nextt[k];
    }
}

void kmp(int a[N], int b[N]) {    
    int nextt[N];    
    int i = 0, j = 0;    
    getnext(b, nextt);    
    while (i < n) {    
        if (j == -1 || a[i] == b[j]) { // 母串不动,子串移动    
            j++;    
            i++;    
        }    
        else {    
            // i不需要回溯了    
            // i = i - j + 1;    
            j = nextt[j];    
        }    
        if (j == m) {    
            printf("%d\n", i - m + 1); // 母串的位置减去子串的长度+1    
            return;    
        }    
    }    
    printf("-1\n");
}    

树状数组

acwing数星星

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
int n;
const int N = 15010, M = 32010;
int tr[M],ans[N];

int lowbit(int x)  //二进制中最后一位1
{
    return x & -x;
}

void update(int x, int c)  // 位置x加c
{
    for (int i = x; i < M; i += lowbit(i)) tr[i] += c;
}

int query(int x)  // 返回前x个数的和
{
    int res = 0;
    for (int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

int main(){
    cin >> n;
    for(int i=1;i<=n;i++){
        int x,y;

        scanf("%d%d",&x,&y);//其实这里 y 并没有什么用

        x++;/*为了防止出现0的情况,给它全体横坐标加上 1 就好了。
        这其实是一个很小的细节,作者但是做的时候没考虑到然后就wa了,而给每个 x 都加上 1 并不会影响结果*/

        update(x,1);//更新一下树状数组,每次都给 x 后面的数据加上 1 

        ans[query(x)]++;/*然后查一下它的前缀和是多少,前缀和是多少就意味着是多少级
        这是一个动态变化的过程,而且后面的一定比前面高
        所以要实时计算*/
     }

     for(int i=1;i<=n;i++){
         printf("%d\n",ans[i]);//输出每一个等级的数量
     }
    
    return 0;
}

线段树

// 建树,分别代表当前节点,区间左端点,区间右端点
void build(int id, int l, int r) {
    if (l == r) {
        pmx[id] = pre[l];
        nmx[id] = nxt[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(id * 2, l, mid);
    build(id * 2 + 1, mid + 1, r);
    pmx[id] = max(pmx[id * 2], pmx[id * 2 + 1]);
    nmx[id] = max(nmx[id * 2], nmx[id * 2 + 1]);
}

//前缀和最大值
int preMax(int id, int l, int r, int s, int t) {
    if (s <= l && t >= r) return pmx[id];
    int mid = (l + r) >> 1;
    int res = -8e18;
    if (s <= mid) res = max(res, preMax(id * 2, l, mid, s, min(t, mid)));
    if (t > mid) res = max(res, preMax(id * 2 + 1, mid + 1, r, max(s, mid), t));
    return res;
}

//后缀和最大值
int nxtMax(int id, int l, int r, int s, int t) {
    if (s <= l && t >= r) return nmx[id];
    int mid = (l + r) >> 1;
    int res = -8e18;
    if (s <= mid) res = max(res, nxtMax(id * 2, l, mid, s, min(t, mid)));
    if (t > mid) res = max(res, nxtMax(id * 2 + 1, mid + 1, r, max(s, mid), t));
    return res;
}

signed main() {
    IOSCC;
    cin >> n >> q;
    rep(i, 1, n) {
        cin >> w[i];
        pre[i] = pre[i - 1] + w[i];
    }
    per(i, 1, n) nxt[i] = nxt[i + 1] + w[i];
    build(1, 1, n);

    
    while (q--) {
        
    }
}

(持续更新。。。)

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值