【AtCoder Grand Contest 035 D】Add and Remove

搜索,动态规划。

题目大意:

给定一个序列 $A_1,A_2,\ldots,A_n$,要执行 $n-2$ 次操作,每次:

  • 选定 $i$($1\lt i\lt$ 序列长度)。
  • 令 $A_{i-1}\leftarrow A_{i-1}+A_i$。
  • $A_{i+1}\leftarrow A_{i+1}+A_i $。
  • 删除 $A_i$。

最后会剩下两个数,求剩下的两个数之和最小是多少。

题解:

考虑对于区间 $[l,r]$,将其变为两个数的和的最小值。

我们考虑 $A_l,A_r$ 对答案的贡献。

令 $f_{l,r,x,y}$ 表示当前考虑的区间为 $[l,r]$,最边上的元素对答案的贡献的系数为 $x,y$ 时,$(l,r)$ 能得到的最小值。

相当于每次枚举最后一次操作的数,并进行合并。

状态数约为 $2^n$,可以直接搜索。

Code:

#include<cstdio>
#include<algorithm>
typedef long long LL;
int A[20],n;
LL f(int l,int r,int x,int y){
    if(r-l<=1)return 0;
    LL p=1e18;
    for(int i=l+1;i<r;++i)
    p=std::min(p,f(l,i,x,x+y)+f(i,r,x+y,y)+(LL)(x+y)*A[i]);
    return p;
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;++i)scanf("%d",A+i);
    printf("%lld",f(0,n-1,1,1)+*A+A[n-1]);
    return 0;
}