给定一个长 的序列 ,每次操作可以选择相邻三个元素 ,将 和 都加上 然后删掉 。操作完后序列会自动补位,即 和 会相邻。
最后会剩下两个元素,最小化它们的和。
,。
直接做不好做,考虑时光倒流。
不难发现每个元素最终都会以某个系数算入答案,考虑一次操作本质上是把 和 的系数都加到 的上,那么设 表示 的系数为 , 的系数为 时 的最小贡献,那么有转移:
减掉是因为重复算了。
这样状态数最多是 的,足以通过本题。
代码如下:
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
typedef long long ll;
const int S=25;
const ll inf=1e17;
int n,a[S];
map<tuple<int,int,int,int>,ll> f;
ll dfs(int l,int r,int fl,int fr)
{
if(l+1==r) return 1ll*a[l]*fl+1ll*a[r]*fr;
tuple<int,int,int,int> u(l,r,fl,fr);
if(f.count(u)) return f[u];
f[u]=inf;
for(int k=l+1;k<=r-1;k++)
{
ll lb=dfs(l,k,fl,fl+fr),rb=dfs(k,r,fl+fr,fr);
f[u]=min(f[u],lb+rb-1ll*(fl+fr)*a[k]);
}
return f[u];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
printf("%lld\n",dfs(1,n,1,1));
return 0;
}