NOIP模擬 naive的瓶子(DP)
阿新 • • 發佈:2018-12-17
【題目分析】
這道題強行讓所有的變為最小值都能拿到95分233333333333
因為都是將一個瓶子的值賦給另一個,那麼我們可以列舉最後的值。
所以一個瓶子要變化為我們列舉的值,要麼直接變為這個值,要麼先變成區間最小值,然後再變成這個值,舉個小栗子:
比如對於3個數2 7 3,我們要將7變成3,如果直接變代價為21,先變成2再變成3代價為20。
所以記錄兩個值取min就行了。(還有就是明明有多組資料為什麼樣例不寫一個1啊qwq)
PS:表示不想打第三題了,1.6k是什麼玩意兒?
【程式碼~】
#include<bits/stdc++.h> using namespace std; typedef long long LL; const LL MAXN=310; const LL INF=1e15; LL n,cnt,ans; LL color[MAXN],minn[MAXN][MAXN]; LL pre[MAXN],dp[MAXN][MAXN]; map<LL,LL> ys; vector<LL> vec[MAXN]; LL Read() { LL i=0,f=1; char c; for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar()); if(c=='-') f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar()) i=(i<<3)+(i<<1)+c-'0'; return i*f; } void init() { memset(minn,0,sizeof(minn)); memset(dp,0,sizeof(dp)); ys.clear(); cnt=0; } int main() { LL T=Read(); while(T--) { init(); n=Read(); for(LL i=1;i<=n;++i) { color[i]=Read(); if(!ys[color[i]]) ys[color[i]]=++cnt,vec[cnt].clear(); vec[ys[color[i]]].push_back(i); pre[i]=pre[i-1]+color[i]; } for(LL i=1;i<=cnt;++i) vec[i].push_back(n+1); for(LL i=1;i<=n;++i) { minn[i][i]=color[i]; for(LL j=i+1;j<=n;++j) minn[i][j]=min(minn[i][j-1],color[j]); } for(LL i=1;i<=n;++i) { dp[i][ys[color[i]]]=color[i]; for(LL j=1;j<=cnt;++j) dp[i][j]+=dp[i-1][j]; } ans=INF; for(LL i=1;i<=n;++i) { LL c=color[i],bef=0; LL last=0; for(LL j=0;j<vec[ys[c]].size();++j) { LL now=vec[ys[c]][j]; LL sum=pre[now-1]-pre[bef],mn=minn[bef+1][now-1]; LL tmp=ys[mn]; last+=min(sum*c,(sum-(dp[now-1][tmp]-dp[bef][tmp]))*mn+mn*c*(now-bef-1)); bef=vec[ys[c]][j]; } ans=min(ans,last); } cout<<ans<<'\n'; } return 0; }