• “蔚来杯“2022牛客暑期多校训练营9 I题: The Great Wall II


    I题: The Great Wall II

    原题链接:https://ac.nowcoder.com/acm/contest/33194/I

    题目大意

    有长度为 n ( 1 ≤ n ≤ 8000 ) n(1\le n\le 8000) n(1n8000) 的序列 a a a 。将其分为 k k k 个非空连续区间的代价是每个区间内 a i a_i ai 的最大值的总和。对于每个 k ∈ [ 1 , n ] k\in [1,n] k[1,n] ,输出最小的代价。

    题解

    考虑动态规划,设 f k , i f_{k,i} fk,i 表示将前 i i i 个数字分为 k k k 的最小代价。
    易得朴素转移式:
    f k , i = min ⁡ x = 1 i ( f k − 1 , x − 1 + max ⁡ y = x i a y ) f_{k,i}=\min_{x=1}^i({f_{k-1,x-1}+\max_{y=x}^i{a_y}}) fk,i=x=1mini(fk1,x1+y=xmaxiay)

    暴力转移复杂度为 O ( n 3 ) O(n^3) O(n3) , 不可行,考虑优化转移复杂度。
    不难发现,当第二项 max ⁡ y = x i a y \max\limits_{y=x}^i{a_y} y=xmaxiay 确定时,对 f k − 1 , x − 1 f_{k-1,x-1} fk1,x1 取最小值即可。
    max ⁡ y = x i a y \max\limits_{y=x}^i{a_y} y=xmaxiay 可画出大致图像如下:

    该项具有单调性,可以用单调栈维护每一个 max ⁡ y = x i a y \max\limits_{y=x}^i{a_y} y=xmaxiay ,同时维护其对应范围内的 min ⁡ f k − 1 , x − 1 \min{f_{k-1,x-1}} minfk1,x1 即可。
    i i i 增加时,图像可能变化为如下状态:


    (绿色为更新的部分,紫色为更新后的有效部分)
    我们可以对新的 max ⁡ y = x i a y \max\limits_{y=x}^i{a_y} y=xmaxiay (绿色部分)在弹出单调栈顶元素的过程中用已有的(第二张图红色部分) min ⁡ f k − 1 , x − 1 \min{f_{k-1,x-1}} minfk1,x1 来更新新的 min ⁡ f k − 1 , x − 1 \min{f_{k-1,x-1}} minfk1,x1
    m n i mn_i mni 表示 max ⁡ y = x i a y = a i \max\limits_{y=x}^i{a_y}=a_i y=xmaxiay=ai 范围内的 min ⁡ f k − 1 , x − 1 \min{f_{k-1,x-1}} minfk1,x1
    最终答案应为 f k , i = min ⁡ ( min ⁡ j ∈ s t a c k ( m n j + v j ) , m n i + a i ) f_{k,i}=\min(\min\limits_{j\in stack}({mn_j}+v_j),mn_i+a_i) fk,i=min(jstackmin(mnj+vj),mni+ai) ,然后将 i i i 放入单调栈即可。
    实际上 f k , t o p = min ⁡ j ∈ s t a c k ( m n j + v j ) f_{k,top}=\min\limits_{j\in stack}({mn_j}+v_j) fk,top=jstackmin(mnj+vj) ,故转移式可简化为 f k , i = min ⁡ ( f k , t o p , m n i + a i ) f_{k,i}=\min(f_{k,top},mn_i+a_i) fk,i=min(fk,top,mni+ai)
    动态规划复杂度为 O ( n 2 ) O(n^2) O(n2) n n n 次单调栈复杂度也为 O ( n 2 ) O(n^2) O(n2) ,可以通过此题。

    注意到更新 f k , i f_{k,i} fk,i 只需要 f k − 1 , j f_{k-1,j} fk1,j ,可以用滚动数组优化内存。

    参考代码

    #include
    using namespace std;
    
    template<class T>inline void read(T&x){
       char c,last=' ';
       while(!isdigit(c=getchar()))last=c;
       x=c^48;
       while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+(c^48);
       if(last=='-')x=-x;
    }
    
    const int MAXN=8e3+5;
    int n;
    int a[MAXN];
    int mn[MAXN];//范围内最小的f
    int stk[MAXN],top;//单调栈
    int f[MAXN],g[MAXN];//滚动数组
    
    int main()
    {
       read(n);
       for(int i=1;i<=n;++i)read(a[i]);
       memset(g,0x3f,sizeof(g));
       g[0]=0;
       for(int k=1;k<=n;++k){
       	f[top=0]=0x3f3f3f3f;//top=0清空栈,同时将f[0]赋值为inf防止空栈时转移出错
       	for(int i=k;i<=n;++i){
       		mn[i]=g[i-1];
       		while(top&&a[stk[top]]<=a[i]){//单调栈
       			mn[i]=min(mn[i],mn[stk[top]]);//维护mn
       			--top;
       		}
       		f[i]=min(f[stk[top]],mn[i]+a[i]);//转移
       		stk[++top]=i;//将i压入栈中
       	}
       	for(int i=k;i<=n;++i)g[i]=f[i];
    		cout<<f[n]<<'\n';//答案即f[n]
       }
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    SpringSecurity6 | 默认登录页
    小啊呜产品读书笔记001:《邱岳的产品手记-05》第9讲 产品案例分析:Hopper的“人工智能” & 第10讲 产品被抄袭了怎么办?
    JVM的生命周期
    构造函数语义学:默认构造函数合成时机
    【四、http】go的http的文件下载
    华为云云耀云服务器L实例评测|企业项目最佳实践之计划任务与Queue队列实践 (十)
    关键词搜索API接口之1688平台
    ActiveMQ 反序列化漏洞(CVE-2015-5254)特征分析
    HTML 文档声明和语言设置
    java集合之Collection接口体系
  • 原文地址:https://blog.csdn.net/Spy_Savior/article/details/126364194