OJ-Problems-Source/POJ/3017.cpp

63 lines
1.6 KiB
C++
Raw Normal View History

2016-09-13 15:23:01 +08:00
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 1000100
#define INF 0x3f3f3f3f
long long a[MAXN];
long long dp[MAXN];
long long t[MAXN];
int tbegin,tend;
int main()
{
int N;
long long M;
scanf("%d %I64d",&N,&M);
tbegin=tend=0;
long long blocksum=0;
int blockbegin=0;
for(int i=1;i<=N;i++)
{
scanf("%I64d",&a[i]);
///如果整个数列中任何一个数超过M那么是无论如何都不能划分的(没有负数存在)
if(a[i]>M)
{
printf("-1\n");
return 0;
}
blocksum+=a[i];
while(blocksum>M)
{
///如果现在假设的连续区块 ID: blockbegin, blockbegin+1 ... i
///求和超过M那么这是一个非法区块需要减去最左端的区块(向右收缩)
blockbegin++;///【疑问】为什么blockbegin要在前面?
blocksum-=a[blockbegin];
}
///队列用于维护每个区块中最大的值的ID
while(tbegin<tend&&a[t[tend-1]]<=a[i]) tend--;
t[tend++]=i;
///队列中最左端的值的ID在blockbegin的左端弹出
while(tbegin<tend&&t[tbegin]<=blockbegin) tbegin++;
///未进行DP前初始化为INF
dp[i]=INF;
int maxvalbegin=blockbegin;
for(int index=tbegin;index<tend;index++)
{
long long tmp=dp[maxvalbegin]+a[t[index]];
dp[i]=min(dp[i],tmp);
maxvalbegin=t[index];
}
}
printf("%I64d\n",dp[N]);
return 0;
}