题目描述 Description
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为
输入描述 Input Description
第一行输入两个整数N,L.接下来N行输入
输出描述 Output Description
输出最小费用
样例输入 Sample Input
5 4
3
4
2
1
4
样例输出 Sample Output
1
题解
首先推荐一篇文章《1D1D动态规划优化初步》,上面详细地介绍了单调栈优化的方法。
令
其中
我们把C数组处理成前缀和,那么
设当
可以证明(也可以打出决策表来观察)这个方程中
注意开longlong,不要unsigned。
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn = 50010;
ll f[maxn], c[maxn];
int n, L, top;
struct stack //决策栈
{
int k, s, t;
stack(int k = 0, int s = 0, int t = 0) :k(k), s(s), t(t) {}
} S[maxn];
void init()
{
scanf("%d%d", &n, &L);
for(int i = 1; i <= n; ++i)
{
scanf("%lld", &c[i]);
c[i] += c[i - 1];
}
}
inline ll w(int x, int y)
{
return (y - x + c[y] - c[x - 1] - L) * (y - x + c[y] - c[x - 1] - L);
}
void work()
{
f[0] = 0;
S[++top] = stack(0, 0, n);
for(int i = 1; i <= n; ++i)
{
int lft = 1, rit = top, mid;
while(lft <= rit) //计算f[i]
{
mid = ((lft + rit) >> 1);
if(S[mid].s <= i && S[mid].t >= i)
{
f[i] = f[S[mid].k] + w(S[mid].k + 1, i);
break;
}
if(i < S[mid].s) rit = mid - 1;
else lft = mid + 1;
}
while(top > 0) //更新决策栈
{
if(f[S[top].k] + w(S[top].k + 1, S[top].s) < f[i] + w(i + 1, S[top].s))
{
lft = S[top].s; rit = S[top].t;
while(lft <= rit)
{
mid = ((lft + rit) >> 1);
if(f[S[top].k] + w(S[top].k + 1, mid) < f[i] + w(i + 1, mid)) lft = mid + 1;
else rit = mid - 1;
}
S[top].t = rit;
break;
}
--top;
}
if(lft <= n) S[++top] = stack(i, lft, n);
}
printf("%lld", f[n]);
}
int main()
{
init();
work();
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/t14t41t/article/details/46728043