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;
}

 

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/83419893
今日推荐