zoukankan      html  css  js  c++  java
  • 【题解】[Codeforces 1400E] Clear the Multiset

    题目链接

    题意

    有一序列 (a),每一步你可以做以下两种操作之一:

    • (a[l..r]) 减一;
    • (a[i])(x)
    • (你需要保证操作后数字非负)

    问最少多少步将整个序列变成 (0)(nleq 5 imes 10^3)(实际可以做到 (O(nlog n)) 甚至 (O(n)))。

    题解

    不会出现左图的情况,左图一定能化为右图且答案不会更劣。

    故递归处理:对于一段,找到其最小值,这一段有两种策略:

    • 这一段的最小值部分用第一种操作,接着序列被 (0) 分成多个部分,每个部分递归找最优解;
    • 这一段全部用第二种操作。

    暴力是 (O(n^2)) 的,用笛卡尔树容易做到 (O(n))(没写)。

    #include<bits/stdc++.h>
    using namespace std;
    int getint(){
        int ans=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            ans=ans*10+c-'0';
            c=getchar();
        }
        return ans*f;
    }
    const int N=5e3+10;
    #define ll long long
    int a[N];
    ll solve(int l,int r){
        int mn=0x7f7f7f7f;
        for(int i=l;i<=r;i++)mn=min(mn,a[i]);
        ll ans=0;
        int t=l;
        for(int i=l;i<=r;i++){
            a[i]-=mn;
            if(a[i]==0){
                if(i!=t)ans+=solve(t,i-1);
                t=i+1;
            }
        }
        if(t!=r+1)ans+=solve(t,r);
        ans+=mn;
        ans=min(ans,r-l+1ll);
        // cerr<<"> "<<l<<" "<<r<<" "<<ans<<endl;
        return ans;
    }
    int main(){
        int n=getint();
        for(int i=1;i<=n;i++)a[i]=getint();
        cout<<solve(1,n);
    }
    
    知识共享许可协议
    若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
  • 相关阅读:
    maven+spark2.0.0最大连通分量
    Eclipse+maven+scala2.11.8+spark2.0.0的环境部署
    杀死mapreduce
    filter-自己的理解
    JS变量声明提升
    js==运算符强制转换规则
    html 文字间距
    如你所见,我开始用微博
    vue数据模拟
    vue项目目录介绍
  • 原文地址:https://www.cnblogs.com/wallbreaker5th/p/13889260.html
Copyright © 2011-2022 走看看