[DP记录]AT5141 [AGC035D] Add and Remove

command_block

2021-04-20 16:13:50

Personal

**题意** : 初始时有长度为 $n$ 的序列 $A$ ,多次进行如下操作,知道只剩两个元素 : - 选择 $2\leq i\leq |A|-1$。 - 令 $A_{i-1},A_{i+1}$ 加上 $A_i$ ,然后将 $A_i$ 从序列中删除。 最小化最后剩下的两个元素的和。 $n\leq 18$ ,时限$\texttt{2s}$。 ------------ 操作只会影响相邻的元素,联想到区间 DP。 若正着考虑,一次操作后,两侧还能互相影响。 不妨倒着考虑。先考虑最后一次操作,此时有 $A_1,A_2,A_3$ ,删除了 $A_2$。 那么 $A_2$ 会加一次到 $A_1$ ,加一次到 $A_3$ ,贡献系数为 $2$。 考虑之前的情况,形如 $A_1,...S_1...,A_2,...S_2...,A_3$ ,其中 $S_1$ 中的元素,有些贡献到了 $A_1$ ,有些贡献到了 $A_2$ 。$S_2$ 中的元素有些贡献到了 $A_3$ ,有些贡献到了 $A_2$。 这里,两种贡献的系数是不同的,$A_1,A_3$ 的贡献系数是 $1$ ,而 $A_2$ 是 $2$。 于是,可以设计如下 $\rm DP$ : 设 $dp[l,r][cl,cr]$ 表示删除区间 $[l,r]$ 内的元素,向 $A_{l-1}$ 的贡献的系数为 $cl$ ,向 $A_{r+1}$ 的贡献的系数为 $cr$ ,贡献的最小值。 答案即为 $dp[2,n-1][1,1]+A_1+A_n$。 有如下转移 : $$dp[l,r][cl,cr]=\min\limits_{k=l}^rdp[l,k-1][cl,cl+cr]+(cl+cr)A_k+dp[k+1,r][cl+cr,cr]$$ 直接进行不记忆化的搜索,复杂度递推式如下 : $$T(n)=\sum\limits_{k=1}^nT(k-1)+T(n-k)$$ 有上界 $O(2^nn)$。 ```cpp #include<algorithm> #include<cstdio> #define ll long long using namespace std; int a[20]; ll dfs(int l,int r,int cl,int cr) { if (l>r)return 0; ll ret=1ll<<60; for (int k=l;k<=r;k++) ret=min(ret,dfs(l,k-1,cl,cl+cr)+1ll*(cl+cr)*a[k]+dfs(k+1,r,cl+cr,cr)); return ret; } int n; int main() { scanf("%d",&n); for (int i=1;i<=n;i++)scanf("%d",&a[i]); printf("%lld",a[1]+dfs(2,n-1,1,1)+a[n]); return 0; } ```