2018.10.26【校內模擬】naive 的瓶子(DP)
阿新 • • 發佈:2018-12-17
傳送門
解析:
首先,這道題用貪心+面向資料程式設計的做法水過去的有點多啊,不過沒辦法,誰叫資料那麼弱呢。。。。
思路:
一看非常小,只有300,頓時明白可以亂搞,列舉每一個瓶子的顏色作為最終顏色,直接求出表示將前個全部塗成當前目標顏色的最小代價,表示將後面全部塗成目標顏色的最小代價,顯然這個求出來後拼接一下就是答案。
那麼考慮DP的轉移,我們每次考慮將一段區間塗成目標顏色,顯然一個瓶子被塗色的方案只有可能是一下兩種: 1.直接被塗成目標顏色 2.先被塗成一個權值較小的顏色,再塗成目標顏色
可以證明,這個權值較小的顏色最優情況下一定是區間最小值,用表求一下就行了。
而且每個瓶子被漆成權值較小的顏色這個過程顯然只會執行一次,如果兩次漆成了其他顏色,顯然是不夠優的。
那麼狀態瞎轉移一下,就討論這兩種情況就行了。
程式碼(首先,博主知道自己的巨集寫的很醜,不過並不想寫函式,您可以假裝這是一個鍛鍊自己程式碼閱讀能力的機會 )(而且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;
}