题目链接 POJ - 3017
超级好的一道题目,从早上先写一个诡异的线段树(当然是错的),逐步推到了单调栈和单调队列,历时很久很久——题记。
将我的解题思路慢慢的展开:
首先,为什么会想到线段树呢,因为这很容易化简成为一个区间dp的形式,就是
这个dp还是比较容易想到的,然后呢,看到这里有一个区间最小值,然后再来就是一个单点更新,以及一个不断放进去的很容易想到用线段树来维护一下这个区间,但是呢,显然是错误的。
列出错误的原因:因为我们不一定取的是区间任意的j这个点和这整个区间的最小的最大值的进行合成,这样实际复杂度又会变得不正确了,所以接下去讲正解。
正解:首先,我们需要明白一个前提,假设是以第i位为结尾的答案值,那么,会发现是单调不减的,这是很重要的一条信息,根据它,我们可以有如下的推断:
如果说,我们的a[ ]数据是升序的,那么肯定是取最早出现的是最优解,譬如说现在有当且仅当二者才有可比性,不然选择一定是更优的(此时)。
所以,我们只要处理出来所有需要比较的点集就可以了,没有必要比较的,我们就把他们删除好了,什么是具有比较效应的呢,也就是我们的a[ ]数组就一定要降序才可能存在,可以取出一些单调递减的a[ ]子序列,满足单调递减,这样才会满足可比较性,然后将它们的值放入一个堆内存最小值就可以了,这里我用的是multiset,因为可能存在重复的值,而且还满足删除和插入的操作,比较灵活。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, top, fail;
ll M, pre[maxN], a[maxN], dp[maxN];
multiset<ll> st;
multiset<ll>::iterator it;
struct node
{
int id; ll aval;
node(int a=0, ll v=0):id(a), aval(v) {}
} que[maxN];
int main()
{
scanf("%d%lld", &N, &M);
bool ok = true;
for(int i=1; i<=N; i++)
{
scanf("%lld", &a[i]); if(a[i] > M) ok = false;
pre[i] = pre[i - 1] + a[i];
dp[i] = INF;
}
if(!ok) { printf("-1\n"); return 0; }
dp[0] = 0;
top = fail = 0;
for(int i=1; i<=N; i++)
{
while(top < fail && pre[i] - pre[que[top].id - 1] > M)
{
it = st.find(dp[que[top].id - 1] + que[top].aval);
st.erase(it);
que[top].id++;
if(top + 1 < fail)
{
if(que[top].id >= que[top + 1].id)
{
top++;
}
else
{
st.insert(dp[que[top].id - 1] + que[top].aval);
}
}
else if(que[top].id >= i)
{
top++;
}
else
{
st.insert(dp[que[top].id - 1] + que[top].aval);
}
}
int old_id = -1;
while(top < fail && que[fail - 1].aval < a[i])
{
old_id = que[fail - 1].id;
it = st.find(dp[que[fail - 1].id - 1] + que[fail - 1].aval);
st.erase(it);
fail--;
}
if(top == fail || que[fail - 1].aval > a[i])
{
que[fail++] = node(~old_id ? old_id : i, a[i]);
st.insert(dp[que[fail - 1].id - 1] + a[i]);
}
dp[i] = *st.begin();
}
printf("%lld\n", dp[N]);
return 0;
}
/*
7 7
0 7 0 0 1 1 2
ans:9
*/