1. 程式人生 > >NOIP模擬 color(DP)

NOIP模擬 color(DP)

額呵呵naive

【題目分析】

這道題強行讓所有的變為最小值都能拿到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;
}