玩具裝箱
阿新 • • 發佈:2022-02-06
這道題顯然可以使用斜率優化DP來解決,但為了理解新知識我還是研究了一下用決策單調性如何解決。
首先列方程。可以得出下面的式子:
\[f[x]=\min\limits_{i=0}^{x-1}\{f[i]+(x-i+1+s_x-s_i-L)^2\} \]對比一下模板式子:
\[f[x]=\min\limits_{i=0}^{x-1}\{f[i]+w(i,x)\} \]是不是一樣的?接下來需要證明這個方程具有單調性,即是要證明題目中的w函式滿足那個奇怪的不等式。可以把一些不變數包裝起來,令
\[S=1-L \]那麼
\[w(i,x)=(s[x]+x-(s_i+i-S))^2 \]可以看出假如把i看成常量時這是一個\(w(i,x)\)
移項得到
\[\forall i\le j,w[i,j]+w[i+1,j+1]\le w[i,j+1]+w[i+1,j] \]於是乎就滿足決策單調性了(證明我也不會,四邊形不等式我還沒有學)。所以呢我們知道了每個點的決策點數列是一個單調不降序列,如何求它呢?有兩種方法,這道題用了第一種二分法。它考慮的是對於每一個點它可能成為哪些點的決策點,很明顯求出來的應該是右端點為終點的一個區間,那麼我們需要做的就是求出左端點的位置。這一點就可以使用二分啦。
一如既往,萬事勝意#include<cstdio> //#define zczc #define int long long const int N=50010; inline void read(int &wh){ wh=0;int f=1;char w=getchar(); while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();} while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();} wh*=f;return; } int m,n,a[N],f[N],s[N],r[N],top; struct node{int id,l;}st[N]; inline int max(int s1,int s2){return s1<s2?s2:s1;} inline int pow(int wh){return wh*wh;} inline int cost(int x,int y){return f[x]+pow(y-x-1+s[y]-s[x]-n);} inline int workf(int wh){ int l=1,r=top,mid; while(l<r)st[mid=l+r+1>>1].l<=wh?l=mid:r=mid-1; return st[l].id; } signed main(){ #ifdef zczc freopen("in.txt","r",stdin); #endif read(m);read(n); for(int i=1;i<=m;i++)read(a[i]),s[i]=s[i-1]+a[i]; st[++top]=(node){0,1}; for(int i=1;i<=m;i++){ f[i]=cost(workf(i),i);r[i]=workf(i); while(top&&st[top].l>i&&cost(st[top].id,st[top].l)>=cost(i,st[top].l))top--; if(top==0){st[++top]=(node){i,i+1};continue;} int l=max(st[top].l,i+1),r=m,mid; while(l<r)cost(st[top].id,mid=l+r>>1)<cost(i,mid)?l=mid+1:r=mid; if(cost(st[top].id,l)>=cost(i,l))st[++top]=(node){i,l}; } printf("%lld",f[m]); return 0; }