题目链接:Association for the Country of Mububa
题意:将这些数划分成n个区间,使得后一个区间里数字的和大于等于前一个区间里数字的和,求最大可以划分多少区间。
思路(gxj大佬的):
- 我们知道所有数到最后都会属于某一个区间,某个数结尾的序列最后一个区间值是最大的
- 我们可以这样想,每个数相当于插入到他前一个数形成的序列结尾,然后就变成了一个一个数插入不断取最优值的过程
- 对于当前这个数来说,插入他之后要么自己构成一个区间,要么把前面一个区间从某个位置截断,截断位置后面的元素与他组成一个区间。
- 对于某状态形成的区间来说最后一个区间值越小越有利于后面的值插入(因为我们要形成的区间数最多),也就是说以某个数结尾的区间最后一个区间越短越好,那么我们插入这个值的时候从当前位置往前一直找到能够满足条件(该数形成的区间大于序列末尾的区间)的数的时候,这个位置一定是当前位置能够形成的最优解。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 3010;
ll n;
ll sum[N];//前缀和
ll num[N];//当前位置所能形成的最大区间数量,dp数组
ll best[N];//以这个数结尾的最后一个区间的值
int main()
{
ll x;
scanf("%lld",&n);
for(ll i = 1; i <= n; i++)
{
scanf("%lld",&x);
sum[i] = sum[i-1] + x;
}
for(ll i = 1; i <= n; i++)
{
for(ll j = i-1; j >= 0; j--)
{
if(sum[i]-sum[j] >= best[j])
{
num[i] = num[j]+1;
best[i] = sum[i]-sum[j];
break;//找到的第一个符合条件的肯定就是最大区间数了
}
}
}
printf("%lld",num[n]);
return 0;
}