zoukankan      html  css  js  c++  java
  • CF E

    题目:传送门

    题意

    给你一个长度为 n 的序列 a,你有两种操作:

    1.选择一段区间 [l, r] 满足区间内所有数都大于 0,对区间内每个数减 1

    2.选择一个 i 和 x,让 a[i] = a[i] - x

    问最少需要操作多少次,使得序列所有数都变为 0

    1 <= n <= 5000; 0 <= ai <= 1e9

    思路

    一. DP

    dp[i][j]:处理完序列前 i 个数,用了 j 次操作 1 的答案

    #include <bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define UI unsigned int
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 0x3f3f3f3f
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    #define lb(x) ((x) & (-(x)))
    #define dbg(x) cout<<#x<<" = "<<x<<endl;
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int n;
    
    int dp[5005][5005];
    
    int a[5005];
    
    void solve() {
    
        scanf("%d", &n);
    
        rep(i, 1, n) scanf("%d", &a[i]);
    
        mem(dp, INF);
    
        rep(i, 1, n) dp[0][min(a[i], i)] = min(a[i], i);
    
        dp[0][0] = 0;
    
        rep(i, 1, n) {
    
            rep(j, 0, n) {
    
                dp[i][min(a[i], j)] = min(dp[i][min(a[i], j)], dp[i - 1][j] + 1);
    
                if(a[i] <= n) {
    
                    if(a[i] <= j) {
    
                        dp[i][a[i]] = min(dp[i][a[i]], dp[i - 1][j]);
    
                    }
    
                    else {
    
                        dp[i][a[i]] = min(dp[i][a[i]], dp[i - 1][j] + a[i] - j);
    
                    }
    
                }
    
            }
    
        }
    
        int ans = INF;
    
        rep(i, 0, n) ans = min(ans, dp[n][i]);
    
        printf("%d
    ", ans);
    
    }
    
    
    int main() {
    
    //    int _; scanf("%d", &_);
    //    while(_--) solve();
    
        solve();
    
        return 0;
    }
    View Code

    二.分治O(n^2)

    #include <bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define UI unsigned int
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 0x3f3f3f3f
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    #define lb(x) ((x) & (-(x)))
    #define dbg(x) cout<<#x<<" = "<<x<<endl;
    using namespace std;
    
    const int N = 1e6 + 5;
    
    const LL mod = 1e9 + 7;
    
    int n;
    
    LL a[N];
    
    LL cal(int l, int r) {
    
        if(l > r) return 0;
    
        if(l == r) return min(a[l], 1LL);
    
        LL mi = a[l]; int pos = l;
    
        rep(i, l, r) {
    
            if(a[i] < mi) {
    
                mi = a[i];
    
                pos = i;
    
            }
    
        }
    
        rep(i, l, r) {
    
            a[i] -= mi;
    
        }
    
        return min(cal(l, pos - 1) + cal(pos + 1, r) + mi, 1LL * (r - l + 1));
    
    }
    
    void solve() {
    
        scanf("%d", &n);
    
        rep(i, 1, n) scanf("%lld", &a[i]);
    
        printf("%lld
    ", cal(1, n));
    
    }
    
    
    int main() {
    
    //    int _; scanf("%d", &_);
    //    while(_--) solve();
    
        solve();
    
        return 0;
    }
    View Code

    三.分治O(nlogn),线段树优化

    #include <bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define UI unsigned int
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 0x3f3f3f3f
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    #define lb(x) ((x) & (-(x)))
    #define dbg(x) cout<<#x<<" = "<<x<<endl;
    using namespace std;
    
    const int N = 1e6 + 5;
    
    const LL mod = 1e9 + 7;
    
    int n;
    
    int a[N];
    
    struct note {
    
        int x, lz, id;
    
    }t[N];
    
    void build(int rt, int l, int r) {
    
        if(l == r) {
    
            t[rt].x = a[l];
    
            t[rt].id = l;
    
            t[rt].lz = 0;
    
            return ;
    
        }
    
        int mid = (l + r) >> 1;
    
        build(rt << 1, l, mid);
    
        build(rt << 1 | 1, mid + 1, r);
    
        if(t[rt << 1].x <= t[rt << 1 | 1].x) {
    
            t[rt].x = t[rt << 1].x;
    
            t[rt].lz = t[rt << 1].lz;
    
            t[rt].id = t[rt << 1].id;
    
        }
    
        else {
    
            t[rt].x = t[rt << 1 | 1].x;
    
            t[rt].lz = t[rt << 1 | 1].lz;
    
            t[rt].id = t[rt << 1 | 1].id;
    
        }
    
    }
    
    void pushdown(int rt) {
    
        if(t[rt].lz) {
    
            t[rt << 1].x -= t[rt].lz;
    
            t[rt << 1 | 1].x -= t[rt].lz;
    
            t[rt << 1].lz = t[rt].lz;
    
            t[rt << 1 | 1].lz = t[rt].lz;
    
            t[rt].lz = 0;
    
        }
    
    }
    
    note query(int rt, int l, int r, int L, int R) {
    
        if(L <= l && r <= R) return t[rt];
    
        pushdown(rt);
    
        int mid = (l + r) >> 1;
    
        note ans;
    
        ans.x = INF; ans.id = 0; ans.lz = 0;
    
        if(L <= mid) {
    
            note tmp = query(rt << 1, l, mid, L, R);
    
            if(tmp.x < ans.x) ans.x = tmp.x, ans.id = tmp.id;
    
        }
    
        if(R > mid) {
    
            note tmp = query(rt << 1 | 1, mid + 1, r, L, R);
    
            if(tmp.x < ans.x) ans.x = tmp.x, ans.id = tmp.id;
    
        }
    
        return ans;
    
    }
    
    void update(int rt, int l, int r, int L, int R, int d) {
    
        if(L <= l && r <= R) {
    
            t[rt].x -= d;
    
            t[rt].lz += d;
    
            return ;
    
        }
    
        pushdown(rt);
    
        int mid = (l + r) >> 1;
    
        if(L <= mid) update(rt << 1, l, mid, L, R, d);
    
        if(R > mid) update(rt << 1 | 1, mid + 1, r, L, R, d);
    
        if(t[rt << 1].x <= t[rt << 1 | 1].x) {
    
            t[rt].x = t[rt << 1].x;
    
            t[rt].id = t[rt << 1].id;
    
        }
    
        else {
    
            t[rt].x = t[rt << 1 | 1].x;
    
            t[rt].id = t[rt << 1 | 1].id;
    
        }
    
    }
    
    int cal(int l, int r) {
    
        if(l > r) return 0;
    
        if(l == r) {
    
            note now = query(1, 1, n, l, r);
    
            if(now.x) return 1;
    
            else return 0;
    
        }
    
        note now = query(1, 1, n, l, r);
    
        update(1, 1, n, l, r, now.x);
    
        return min(cal(l, now.id - 1) + cal(now.id + 1, r) + now.x, (r - l + 1));
    
    }
    
    void solve() {
    
        scanf("%d", &n);
    
        rep(i, 1, n) scanf("%d", &a[i]);
    
        build(1, 1, n);
    
        printf("%d
    ", cal(1, n));
    
    }
    
    
    int main() {
    
    //    int _; scanf("%d", &_);
    //    while(_--) solve();
    
        solve();
    
        return 0;
    }
    View Code

     

  • 相关阅读:
    NSString
    xib和storyboard的使用方法
    drawRect画线和使用CGContext
    CGAffineTransform动画
    【概念】静态成员
    【c#】Application.Exit和Close有什么不同
    【c#】const和readonly关键字
    【概念】设计模式
    【概念】常见数据结构与算法
    【概念】索引器
  • 原文地址:https://www.cnblogs.com/Willems/p/13582611.html
Copyright © 2011-2022 走看看