1. 程式人生 > >單調佇列優化dp--bzoj1705

單調佇列優化dp--bzoj1705

傳送門 暴力的dp是1e9的,是這樣一樣轉移式: f[i][j]=min{f[i1][k]+jkc}+(ja[i])2f[i][j]=min\{f[i-1][k]+|j-k|*c\}+(j-a[i])^2 然後分類討論去掉絕對值 f[i][j]={min{f[i1][k]+jckc}+(ja[i])2j>=kmin{f[i1][k]jc+kc}+(ja[i])2j<kf[i][j]=\begin{cases}min\{f[i-1][k]+j*c-k*c\}+(j-a[i])^2&j>=k\\min\{f[i-1][k]-j*c+k*c\}+(j-a[i])^2&j<k\end{cases}

然後發現後面那一堆可以單調佇列優化,其實也不算單調佇列 就是把迴圈順序改一下記一個最小值就可以了 如果從前往後迴圈就能保證j>=k,從後往前就能保證j<k,取min就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue> #define maxn 100005 #define inf 0x3f3f3f3f #define LL long long using namespace std; int n,c,a[maxn],f[2][105],mx,now,ans=inf; inline int rd(){ int x=0,f=1;char c=' '; while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar(); while(c<='9' && c>='0') x=x*10+c-'0',c=getchar(
); return x*f; } int main(){ n=rd(); c=rd(); for(int i=1;i<=n;i++) a[i]=rd(),mx=max(mx,a[i]); for(int i=0;i<=mx;i++) f[1][i]=f[0][i]=inf; for(int i=a[1];i<=mx;i++) f[now][i]=(i-a[1])*(i-a[1]); for(int i=2;i<=n;i++){ now^=1; int k=inf; for(int j=a[i-1];j<=mx;j++){ k=min(k,f[now^1][j]-j*c); if(j>=a[i]) f[now][j]=k+(j-a[i])*(j-a[i])+c*j; } k=inf; for(int j=mx;j>=a[i];j--){ k=min(k,f[now^1][j]+j*c); f[now][j]=min(f[now][j],k+(j-a[i])*(j-a[i])-c*j); } for(int j=0;j<=mx;j++) f[now^1][j]=inf; } for(int i=a[n];i<=mx;i++) ans=min(ans,f[now][i]); printf("%d\n",ans); return 0; }