题目大意:
你可以把第 i i i座塔和 i + 1 i+1 i+1座或 i − 1 i-1 i−1座合并成一个
使得到的那座塔的高度是原来两座塔的和
问最使序列变成严格不增最小合并次数
解题思路:
首先我想到的是贪心,然而贪心果断行不通(自证)
但是我们可以结合贪心去
d
p
dp
dp
就是肯定对于某个
d
p
dp
dp方程而言肯定是前面的高度越小越好
然后看到严格不增,那么如果 i i i前面的塔符合要求,我们只要知道最后一个的高度就可以往后推
所以我们可以用 d p dp dp做
s
[
i
]
s[i]
s[i]代表前缀和
L
[
i
]
L[i]
L[i]代表到i高度(合并之后)
d
p
[
i
]
dp[i]
dp[i]表示到i都符合要求的最小合并次数
那么就有转移方程
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
const int Maxn=5e3+5;
const int inf=1<<30;
inline int R()//快读
{
char c;int res;
while((c=getchar())>'9'||c<'0');res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
return res;
}
int L[Maxn],dp[Maxn],S[Maxn],n;
int main()
{
n=R();
for(int i=1;i<=n;i++)//初始化
S[i]=S[i-1]+R(),dp[i]=L[i]=inf;
for(int i=1;i<=n;i++)
for(int j=0;j<=i;j++)
// s[i] - s[j] : 就是把j+1到i都合并到i里面去
// 它必须要比L[j]就是第j个的高度还要大
if(S[i]-S[j]>=L[j]&&dp[i]>=dp[j]+i-j-1)//状态转移
dp[i]=dp[j]+i-j-1,L[i]=min(L[i],S[i]-S[j]);
printf("%d\n",dp[n]);
return 0;
}