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

"蔚来杯"2022牛客暑期多校训练营9-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],输出最小总和。

解题思路

d p i , j dp_{i,j} dpi,j表示将前 i i i个数分成 j j j个区间的最小总和。则 d p i , j = m i n ( d p k ∈ [ j − 1 , i ] , j − 1 + m a x ( a k , a k + 1 ⋅ ⋅ ⋅ a i − 1 , a i ) ) dp_{i,j}=min(dp_{k\in[j-1,i],j-1}+max(a_k,a_{k+1}···a_{i-1},a_i)) dpi,j=min(dpk[j1,i],j1+max(ak,ak+1⋅⋅⋅ai1,ai)),\,枚举 i , j , k , a k , a k + 1 ⋅ ⋅ ⋅ a i − 1 , a i i,j,k,a_k,a_{k+1}···a_{i-1},a_i i,j,k,ak,ak+1⋅⋅⋅ai1,ai需要 O ( n 4 ) O(n^4) O(n4)
发现 d p k ∈ [ j − 1 , i ] , j − 1 + m a x ( a k , a k + 1 ⋅ ⋅ ⋅ a i − 1 , a i ) dp_{k\in[j-1,i],j-1}+max(a_k,a_{k+1}···a_{i-1},a_i) dpk[j1,i],j1+max(ak,ak+1⋅⋅⋅ai1,ai) k ∈ [ j − 1 , i ] m a x ( a k , a k + 1 ⋅ ⋅ ⋅ a i − 1 , a i ) k\in[j-1,i]max(a_k,a_{k+1}···a_{i-1},a_i) k[j1,i]max(ak,ak+1⋅⋅⋅ai1,ai)单调递减,可以用单调栈维护。时间降到 O ( n 2 ) O(n^2) O(n2).

代码实现

#include<bits/stdc++.h>
using namespace std;
const int N=8e3+5;
int f[2][N],g[N],mi[N],stk[N],n,a[N],top;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i],f[0][i]=0x3f3f3f3f;
	for(int k=1;k<=n;k++){
		int id=k&1;
		f[id][top=0]=0x3f3f3f3f;
		for(int i=k;i<=n;i++){
			mi[i]=f[id^1][i-1];
			while(top&&a[stk[top]]<=a[i]){
				mi[i]=min(mi[i],mi[stk[top]]);
				top--;
			}
			f[id][i]=min(f[id][stk[top]],mi[i]+a[i]);
			stk[++top]=i;
		}
		cout<<f[id][n]<<'\n';
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值