您的位置:首页 > 其它

BZOJ 1096 ZJOI2007 仓库设计 斜率优化dp

2016-01-05 19:20 375 查看
太高兴了,这是我第一次自己独立思考的斜率优化dp,从头到尾都是自己想的。(相信自己,能行的,不过也做了40分钟了)。 这道题目还好吧! 看到之后第一反应是想设从工厂0运到工厂i 总共需要 tot[i] 的费用, 用 p[i] 表示从山顶到工厂 i 总共的产品数, 再用 x[i] 表示从工厂0到工厂 i 的距离, 那么状态转移方程就是 f[i] = min{f[j] + tot[i] - tot[j] - p[j] * (x[i] - x[j] ) + c[i] } ,很明显由于数据有 n <= 1000000 不能 n ^ 2 的朴素算法, 要进行优化。 先看一下状态转移方程, 除了 f[j] 不定之外, 其他的在数据给出时都已确定(换句话说,满足无后效性,只要保证之前处理f[i]时,f[i]是最小就好),可以考虑斜率优化。

那么设 j < k , 目前正在处理 f[i]; 如果 j 比 k 差的话, 那么 f[j] + tot[i] - tot[j] - p[j] * (x[i] - x[j] ) >= f[k] + tot[i] - tot[k] - p[k] * (x[i] - x[k])

移项化简得当 f[j] - f[k] - tot[j] + tot[k] + p[j] * x[j] - p[k] * x[k] >= x[i] * (p[j] - p[k]) 时 j 比 k 差。

又因为求的是最小值所以要维护一个下凸函数。加油,努力。(1700毫秒)

#include<cstdio>
#include<iostream>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define maxn 1000005
#define ll long long
using namespace std;

int read()
{
int s = 0, t = 1; char c = getchar();
while( !isdigit(c) ){
if( c == '-' )t = -1; c = getchar();
}
while( isdigit(c) ){
s = s * 10 + c -'0'; c = getchar();
}
return s * t;
}

ll tot[maxn] = {0}, f[maxn] = {0}, c[maxn] = {0}, p[maxn] = {0}, x[maxn] = {0};
int q[maxn] = {0};

ll S(int k,int j)
{
return f[j] - f[k] + p[j] * x[j] - p[k] * x[k] + tot[k] - tot[j];
}

ll G(int k,int j)
{
return p[j] - p[k];
}

int main()
{
int n = read();
rep(i,1,n){
x[i] = read(), p[i] = read(), c[i] = read();  p[i] += p[i-1];
}
rep(i,1,n){
tot[i] = p[i-1] * (x[i]-x[i-1]) + tot[i-1];
}
int l = 0, r = 0; q[r] = 0;
rep(i,1,n){
while( l < r && S(q[l+1],q[l]) >= G(q[l+1],q[l]) * x[i] ) l++;
int j = q[l];
f[i] = f[j] + tot[i] - tot[j] + c[i] - p[j] * (x[i]-x[j]);
while( l < r && S(q[r],q[r-1]) * G(i, q[r]) >= S(i,q[r]) * G(q[r],q[r-1]) ) r--;
q[++r] = i;
}
cout<<f
<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: