洛谷P3195 玩具裝箱

P3195 [HNOI2008]玩具裝箱TOY ide

第一道斜率優化題。優化

首先一個基本的狀態轉移方程是spa

要使f[i]最小,即b最小。code

對於每一個j,能夠表示爲一個點。blog

而後咱們取固定斜率時截距最小的便可,高中線性規劃。隊列

單調隊列維護下凸包。get

而後每次二分出j,轉移。編譯器

記得給(0,L * L)賦初值。io

記得開long long編譯

++,--最好別隨便用,編譯器的不一樣會讓你爆0...

 1 #include <cstdio>
 2 
 3 typedef long long LL;
 4 const int N = 50010;
 5 
 6 LL sum[N], g[N], p[N], top;
 7 LL f[N], y[N];
 8 
 9 inline double slope(int i, int j) {
10     return ((double)(y[j] - y[i])) / (g[j] - g[i]);
11 }
12 
13 inline int get(int i) {
14     if(i == 1) {
15         return 0;
16     }
17     double k = 2.0 * g[i];
18     int l = 0, r = top, mid;
19     while(l < r) {
20         mid = (l + r) / 2;
21         //printf("%lf %lf \n", slope(p[mid], p[mid + 1]), k);
22         if(slope(p[mid], p[mid + 1]) < k) {
23             l = mid + 1;
24         }
25         else {
26             r = mid;
27         }
28     }
29     //printf("i = %d  r = %d  j = %d \n", i, r, p[r]);
30     return p[r];
31 }
32 
33 int main() {
34     //freopen("in.in", "r", stdin);
35     LL n, L;
36     scanf("%lld%lld", &n, &L);
37     L++;
38     for(int i = 1; i <= n; i++) {
39         LL x;
40         scanf("%lld", &x);
41         sum[i] = sum[i - 1] + x;
42         g[i] = i + sum[i];
43     }
44     y[0] = L * L;
45     for(int i = 1; i <= n; i++) {
46         // f[i] = f[j] + (g[i] - g[j] - L) ^ 2
47         int j = get(i);
48 
49         f[i] = f[j] + (g[i] - g[j] - L) * (g[i] - g[j] - L);
50         y[i] = f[i] + (g[i] + L) * (g[i] + L);
51         //printf("y[%d] = %d \n", i, y[i]);
52 
53         p[++top] = i;
54         while(top > 1 && slope(p[top - 2], p[top - 1]) >= slope(p[top - 1], p[top])) {
55             p[top - 1] = p[top];
56             top--;
57         }
58     }
59 
60     /*for(int i = 1; i <= n; i++) {
61         printf("%lld ", f[i]);
62     }
63     puts("");*/
64     printf("%lld", f[n]);
65     return 0;
66 }
AC代碼

[update20181208]今天又考了一次玩具裝箱,發現了一個問題.......怎麼能把點的座標直接帶入到斜截式裏面啊!!!!

只知道y - y0 = k(x - x0),歷來沒聽過y0 = kx0 + b啊啊啊!!!

關於上面那個的解釋:(感謝某蔣姓巨佬爲我講解)

上面那個式子化簡爲2gi * gj + C = F(j)

考慮有某條直線過點(gj, F(j)),且方程爲kx + b = y,其中k = 2gi

那麼將點帶入,可得:k * gj + b = F(j)

故上面那個等式即爲直線的方程。

y - F(j) = 2gi(x - gj)

y - F(j) = 2gi * x - 2gi * gj

而後反正瞎搞一搞就好了啦我也無論了啊啊啊啊阿斜率優化好難啊啊我到底在寫什麼東西啊

相關文章
相關標籤/搜索