2018年10月31日提高组 T2 B

版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/83590752

大意

给定 n n 个数,若合并相邻两个数 a i , a i + 1 a_i,a_{i+1} 的代价为 a i × a i + 1 a_i\times a_{i+1} ,然后变成 a i a_i ,求合并所有数的代价


思路

比较容易想到一种不能 A A 的局面贪心

直接找到最小值,然后合并即可,复杂度 O ( n ) O(n) ,期望得分:30,实际得分:80


这种贪心错误的原因很明显啊,所以我们想到了另一种贪心

枚举所有的数,然后计算左边的数合并起来的最小代价,右边的数合并起来的最小代价,再合并即可,时间复杂度: O ( n 2 ) O(n^2) ,期望得分:100,实际得分:100


听大佬说还可以区间 d p dp ,可本蒟蒻不会啊。。。


代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ri register int
#define min(a,b) (a)<(b)?(a):(b)
using namespace std;int t,n;
long long ans,a[301],f[301];
inline void tx(register int x)
{
	long long s=0;
	memcpy(f,a,sizeof(f));
	for(register int i=1;i<n;i++)//合并左边的数
	if(f[i]!=x&&f[i+1]!=x&&f[i]>f[i+1]&&x*f[i+1]+f[i]*f[i+1]<x*f[i])
	{
		s+=f[i]*f[i+1];
		f[i]=f[i+1];
	}
	for(register int i=2;i<=n;i++)//合并右边的数
	if(f[i]!=x&&f[i-1]!=x&&f[i]>f[i-1]&&x*f[i-1]+f[i]*f[i-1]<x*f[i])
	{
		s+=f[i]*f[i-1];
		f[i]=f[i-1];
	}
	for(register int i=1;i<=n;i++) if(f[i]!=x) s+=f[i]*x;//最后即为区间最小值
	ans=min(ans,s);//保存最小值
	return;
}
signed main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);ans=99999999999999ll;
		for(ri i=1;i<=n;i++) scanf("%lld",&a[i]);
		for(ri i=1;i<=n;i++) tx(a[i]);//判断是否可以
		printf("%lld\n",ans);//输出
	}
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/83590752