1. 程式人生 > >2018.10.26【校內模擬】naive 的瓶子(DP)

2018.10.26【校內模擬】naive 的瓶子(DP)

傳送門

解析:

首先,這道題用貪心+面向資料程式設計的做法水過去的有點多啊,不過沒辦法,誰叫資料那麼弱呢。。。。

思路:

一看nn非常小,只有300,頓時明白可以亂搞,O(n)O(n)列舉每一個瓶子的顏色作為最終顏色,直接O(n2)DPO(n^2)DP求出fif_i表示將前ii個全部塗成當前目標顏色的最小代價,gig_i表示將後面ini-n全部塗成目標顏色的最小代價,顯然這個求出來後拼接一下就是答案。

那麼考慮DP的轉移,我們每次考慮將一段區間塗成目標顏色,顯然一個瓶子被塗色的方案只有可能是一下兩種: 1.直接被塗成目標顏色 2.先被塗成一個權值較小的顏色,再塗成目標顏色

可以證明,這個權值較小的顏色最優情況下一定是區間最小值,用STST表求一下就行了。

而且每個瓶子被漆成權值較小的顏色這個過程顯然只會執行一次,如果兩次漆成了其他顏色,顯然是不夠優的。

那麼狀態瞎轉移一下,就討論這兩種情況就行了。

程式碼(首先,博主知道自己的巨集寫的很醜,不過並不想寫函式,您可以假裝這是一個鍛鍊自己程式碼閱讀能力的機會 )(而且DP的轉移有一點點問題,不過資料太弱了,懶得改了):

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define
gc getchar
#define pc putchar #define cs const inline int getint(){ re int num; re char c; while(!isdigit(c=gc()));num=c^48; while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48); return num; } cs int N=302; cs int INF=0x3f3f3f3f; int logn[N]; int minn[N][10]; int col[N],a[N],sum[N]; int
n; ll f[N],g[N]; ll ans; #define s(l,r) (sum[(r)]-sum[(l)-1]) #define Min(l,r) min(minn[(l)][logn[(r)-(l)+1]],minn[(r)-(1<<logn[(r)-(l)+1])+1][logn[(r)-(l)+1]]) int T; signed main(){ for(int re i=2;i<=300;++i)logn[i]=logn[i>>1]+1; T=getint(); while(T--){ n=getint(); for(int re i=1;i<=n;++i) sum[i]=sum[i-1]+(minn[i][0]=col[i]=getint()); for(int re i=1;i<=logn[n];++i) for(int re j=1;j+(1<<i)-1<=n;++j) minn[j][i]=min(minn[j][i-1],minn[j+(1<<i-1)][i-1]); ans=1ll*INF*INF; for(int re k=1;k<=n;++k){ memset(f,INF,sizeof f); f[k]=min(1ll*col[k]*sum[k-1],1ll*sum[k-1]*Min(1,k)+1ll*col[k]*Min(1,k)*(k-1)); for(int re i=k+1;i<=n;++i){ if(col[i]==col[k]){ f[i]=f[i-1]; continue; } for(int re j=i-1;j>=k;--j){ f[i]=min(f[i],f[j]+1ll*s(j+1,i)*col[k]); f[i]=min(f[i],f[j]+1ll*Min(j+1,i)*s(j+1,i)+1ll*col[k]*Min(j+1,i)*(i-j)); } } int last=n; while(col[last]!=col[k])--last; memset(g,INF,sizeof g); g[last]=min(1ll*col[k]*s(last+1,n),1ll*s(last+1,n)*Min(last,n)+1ll*col[last]*Min(last,n)*(n-last)); for(int re i=last-1;i;--i){ if(col[i]==col[last]){ g[i]=g[i+1]; continue; } for(int re j=i+1;j<=last;++j){ g[i]=min(g[i],g[j]+1ll*s(i,j-1)*col[last]); g[i]=min(g[i],g[j]+1ll*Min(i,j-1)*s(i,j-1)+1ll*col[last]*Min(i,j-1)*(j-i)); } } f[0]=g[n+1]=0; for(int re i=0;i<=n;++i)ans=min(ans,f[i]+g[i+1]); } cout<<ans<<"\n"; } return 0; }