ZJOI 2007 倉庫建設
阿新 • • 發佈:2018-12-17
注意到我們所有的東西都只能轉移到後面,那麼可以考慮dp
用dp[i]表示以i結尾建立倉庫的最小花費
那麼dp[i] = min(dp[i], dp[j] + w[i] + sigma(dis[i] - dis[k]) * num[k])
這個dp直接轉移是n ^ 2
考慮優化這個dp
然後他是由前面所有的轉移過來,而且還有其他的陣列來計算答案,一般的資料結構解決不了這個問題,那麼就xjb劃式子搞搞,然後就可以推出一個東西
用sumd[i] 表示num[i] * dis[i]的字首和
用sumn[i]表示num[i]的字首和
考慮一個k比j更優秀,那麼可以推出 dis[i] > (dp[k] + sumd[k] - dp[j] - sumd[j]) / (sumn[k] - sumn[j])
然後就是斜率優化的慣用套路
每次新加入一個的時候看看隊首是否合法,把不合法的全部彈掉,然後更新dp值
例如 while (head < tail && slope(q[head], q[head + 1]) < 1.0 * dis[i]) head++;
然後得到dp[i]的值
再看看當前值是否能比隊尾值,把廢物搞掉
例如 while (head < tail && slope(q[tail - 1], q[tail]) > slope(q[tail], i)) tail--;
然後把這個B加入佇列中
斜率優化主要是要看的出來,然後能推出式子,最重要的是要能劃出一個斜率的形式,例如y[i] - y[j] / x[i] - x[j]這種
程式碼如下
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define ll long long using namespace std; int readint() { int rt = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { rt = (rt << 1) + (rt << 3) + ch - '0'; ch = getchar(); } return rt * f; } ll readll() { ll rt = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { rt = (rt << 1) + (rt << 3) + ch - '0'; ch = getchar(); } return rt * f; } const int maxn = 1e6 + 5; int n; ll num[maxn], dis[maxn], w[maxn], sumd[maxn], sumn[maxn], dp[maxn]; int q[maxn << 1]; double slope(int k, int j) { return 1.0 * (dp[k] + sumd[k] - dp[j] - sumd[j]) / (1.0 * sumn[k] - sumn[j]); } int main() { n = readint(); for (int i = 1; i <= n; i++) { dis[i] = readll(), num[i] = readll(), w[i] = readll(); } for (int i = 1; i <= n; i++) { sumd[i] = sumd[i - 1] + num[i] * dis[i]; sumn[i] = sumn[i - 1] + num[i]; } int head = 1, tail = 0; q[++tail] = 0; for (int i = 1; i <= n; i++) { while (head < tail && slope(q[head], q[head + 1]) < 1.0 * dis[i]) head++; dp[i] = dp[q[head]] + dis[i] * (sumn[i] - sumn[q[head]]) - sumd[i] + sumd[q[head]] + w[i]; while (head < tail && slope(q[tail - 1], q[tail]) > slope(q[tail], i)) tail--; q[++tail] = i; } printf("%lld\n", dp[n]); return 0; }