- 题目描述 Description
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为x=j?i+Sigmajk=i(Ck) 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(x?L)2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小.
- 输入描述 Input Description
第一行输入两个整数N,L.接下来N行输入Ci,1≤N≤50000,1≤L,Ci≤107
- 输出描述 Output Description
输出最小费用
- 样例输入 Sample Input
5 4
3
4
2
1
4
- 样例输出 Sample Output
1
- 题解
首先推荐一篇文章《1D1D动态规划优化初步》,上面详细地介绍了单调栈优化的方法。
令f[i]表示前i件玩具放入容器内的最小代价,通过一些简单的分析,我们可以得到这样一个DP方程:
f[i]=mini?1j=0{f[j]+w(j+1,i)},(f[0]=0),
其中w(x,y)=(y?x+Sigmayi=x(Ci)?L)2,
我们把C数组处理成前缀和,那么w(x,y)可在O(1)的时间内算出,直接求解的话整个方程的时间复杂度是O(n2)。
设当f[i]取到最优值时f[i]=f[k]+w(k+1,i),则记f[i]由决策k转移过来。//那么i=1时应有k=0。
可以证明(也可以打出决策表来观察)这个方程中k的值是单调不降的。所以可以套用单调栈优化,时间复杂度O(nlog2n)通过本题。
注意开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;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。