大意
给定 n n n个数,若合并相邻两个数 a i , a i + 1 a_i,a_{i+1} ai,ai+1的代价为 a i × a i + 1 a_i\times a_{i+1} ai×ai+1,然后变成 a i a_i ai,求合并所有数的代价
思路
比较容易想到一种不能 A A A的局面贪心
直接找到最小值,然后合并即可,复杂度 O ( n ) O(n) O(n),期望得分:30,实际得分:80
这种贪心错误的原因很明显啊,所以我们想到了另一种贪心
枚举所有的数,然后计算左边的数合并起来的最小代价,右边的数合并起来的最小代价,再合并即可,时间复杂度: O ( n 2 ) O(n^2) O(n2),期望得分:100,实际得分:100
听大佬说还可以区间 d p dp 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);//输出
}
}