1. 程式人生 > >BZOJ 1010 [HNOI2008]玩具裝箱toy 斜率優化dp

BZOJ 1010 [HNOI2008]玩具裝箱toy 斜率優化dp

inf sign http mes while bsp 情況 ++ can

[HNOI2008]玩具裝箱toy

斜率優化dp:

好久沒有寫斜率優化dp都忘記了這個東西到底是怎麽回事。

對於斜率優化dp來說, 我們可以將一個 轉移方程轉換成 y = k x + b.

其中要求的東西在b上。

註意: 現在是給定了一堆點(x,y), 讓你在固定k的前提下求出最小/最大的b是多少。

如果現在是維護最小的b。

那麽我們需要維護出一個下凸殼。

如果k是遞增的話, 我們可以不斷的將隊頭不是最優的(x,y)去掉,留下最優的點作為對頭。(講道理,如果在求最小b的情況下, 這個k應該不會遞減,不然就顯得特別蠢,23333)。

如果k是隨意的話,我們可以把下凸殼維護出來,然後二分找到最優解。

題解:

一開始列的方程應該為 dp[i] = min(dp[j] + (i-j-1 + sum[i] - sum[j] - L)^2)。

因為n=1e5,所以這個題目不能用n^2去轉移。

可以令A = sum[i] + i, B = sum[j]+j+L+1

化簡前面的式子,可得:dp[j] + B^2 = 2 * A * B + dp[i] - A^2.

y = dp[j] + B ^ 2, k = 2 * A, x = B, dp[i] - A ^ 2。

也就是上面說的y = k * x + b了。

通過維護一個下凸殼,我們可以在o(n)的復雜度內求出答案。

代碼:

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define
lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 2e5 + 100; int n, L; int a[N]; int sta[N]; LL sum[N]; LL dp[N]; LL calb(int id, int i){ LL B = sum[id] + id + L + 1; LL A = sum[i] + i; return dp[id] + B * B - 2 * A * B; } double slope(int x, int y){ double x1 = sum[x] + x + L + 1; double y1 = dp[x] + x1 * x1; double x2 = sum[y] + y + L + 1; double y2 = dp[y] + x2 * x2; return (y1-y2) / (x1-x2); } int Ac(){ scanf("%d%d", &n, &L); for(int i = 1; i <= n; ++i){ scanf("%d", &a[i]); sum[i] = sum[i - 1] + a[i]; } int L = 1, R = 1; sta[0] = 0; for(int i = 1; i <= n; ++i){ while(L < R && calb(sta[L], i) > calb(sta[L+1], i)) ++L; LL A = sum[i] + i; dp[i] = calb(sta[L], i) + A * A; while(L < R && slope(i,sta[R]) < slope(sta[R], sta[R-1])) --R; sta[++R] = i; } printf("%lld\n", dp[n]); return 0; } int main(){ Ac(); return 0; }
View Code

BZOJ 1010 [HNOI2008]玩具裝箱toy 斜率優化dp