http://www.lydsy.com/JudgeOnline/problem.php?id=1096
这道题和那道锯木厂选址很像,
按照自己的思维习惯我把所有的点翻转了,即从山底到山顶.
dist[i]表示第i个点到第一个点的距离,c[i]为在第i个点建的费用,p[i]表示第i个点的存货
dp[i] = min(dp[j-1]+∑p[k]*(dist[k]-dist[j])+c[j])
设sp[i] = ∑p[k] (1 <= k <= i)
spd[i] = ∑p[k]*dist[k] (1 <= k <= i)
dp[j-1]+∑p[k]*(dist[k]-dist[j])+c[j]
= dp[j-1]+spd[i]-spd[j-1]-(sp[i]-sp[j-1])*dist[j]+c[j]
= dp[j-1]+spd[j-1]+sp[j-1]*dist[j]+c[j]-sp[i]*dist[j]+spd[i]
用y表示dp[j-1]+spd[j-1]+sp[j-1]*dist[j]+c[j]
x表示dist[j]
a表示sp[i]
就变成了斜率优化的形式G = -ax+y, a单调递增
dp[i] = min(G)+spd[i]
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> #include <bitset> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::stringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; using std::unique; using std::lower_bound; using std::random_shuffle; using std::bitset; using std::upper_bound; using std::multiset; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; typedef LL TY; typedef long double LF; const int MAXN(1000010); const int MAXM(100010); const int MAXE(100010); const int MAXK(6); const int HSIZE(31313); const int SIGMA_SIZE(26); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); const int MOD(20100403); const double EPS(1e-7); const LF PI(acos(-1.0)); template<typename T> void checkmax(T &a, T b){if(b > a) a = b;} template<typename T> void checkmin(T &a, T b){if(b < a) a = b;} template<typename T> T ABS(const T &a){return a < 0? -a: a;} int que[MAXN]; int front, back; LL dist[MAXN], spd[MAXN], sp[MAXN], table[MAXN]; int C[MAXN]; LL Y(int ind){ return table[ind-1]+C[ind]+sp[ind-1]*dist[ind]-spd[ind-1];} LL X(int ind){ return dist[ind];} int main() { int n; while(~scanf("%d", &n)) { for(int i = n; i >= 1; --i) scanf("%lld%lld%d", dist+i, sp+i, C+i); LL temp = dist[1]; for(int i = 1; i <= n; ++i) { dist[i] = temp-dist[i]; spd[i] = spd[i-1]+sp[i]*dist[i]; sp[i] += sp[i-1]; } int ti = 1; while(sp[ti] == 0) table[ti++] = 0; front = 0; back = -1; que[++back] = ti; for(int i = ti; i <= n; ++i) { LL ty = Y(i), tx = X(i); LL a = sp[i]; while(back-front > 0 && (ty-Y(que[back-1]))*(tx-X(que[back])) >= (ty-Y(que[back]))*(tx-X(que[back-1]))) --back; que[++back] = i; while(back-front > 0 && (-a)*X(que[front+1])+Y(que[front+1]) <= (-a)*X(que[front])+Y(que[front])) ++front; table[i] = (-a)*X(que[front])+Y(que[front])+spd[i]; } printf("%lld\n", table[n]); } return 0; }