题目背景
loidc来到了NOI的赛场上,他在那里看到了好多神犇。
题目描述
神犇们现在正排成一排在刷题。每个神犇都有一个能力值p[i]。loidc认为坐在附近的金牌爷能力参差不齐非常难受。于是loidc便想方设法对神犇们进行人道主义合并。
loidc想把神犇的能力值排列成从左到右单调不减。他每次可以选择一个神犇,把他合并到两侧相邻的神犇上。合并后的新神犇能力值是以前两位犇的能力值之和。每次合并完成后,被合并的两个神犇就会消失。合并后的新神犇不能再分开(万一他俩有女朋友咋办)因此每次合并后神犇的总数会减1.
loidc想知道,想治好他的强迫症需要合并多少次
输入输出格式
输入格式:第一行一个整数 n。
第二行 n 个整数,第 i 个整数表示 p[i]。
输出格式:loidc需要合并的次数
输入输出样例
输入样例#1:
8
1 9 9 4 1 2 2 9
输出样例#1:
3
说明
对于 50%的数据,0< n <=5000。
对于 100%的数据,0< n <=200000,0< p[i] <=2147483647,p 均为随机生成。
这题大家的第一印象大概都是贪心,但是我们的熊本熊在洛谷的题解中给出了反例,而正解是DP。
f[i]表示前i个数最小要花费多少次达到要求,
pre[i]表示前i个数中最大的数,
于是我们就有了下面的代码(如有雷同,纯属故意)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define il inline
#define ll long long
#define db double
using namespace std;
il ll gl()
{
int x=0,y=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
y=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*y;
}
ll sum[200045];
ll f[200045];
ll pre[200045];
int main()
{
int n;
cin>>n;
ll x;
for(int i=1;i<=n;i++)
{
x=gl();
sum[i]=sum[i-1]+x;
}
for(int i=1;i<=n;i++)
{
int j;
for(j=i-1;j>=0;j--)
if(sum[i]-sum[j]>=pre[j])
break;
f[i]=f[j]+i-j-1;
pre[i]=sum[i]-sum[j];
}
printf("%lld\n",f[n]);
return 0;
}