[AGC035D] Add and Remove
非常妙的一道题, 考虑最后剩下一定是 \(a[1]\) 和 \(a[n]\), 我们就想一想可不可以算每个数会对答案产生多少贡献?我们如果考虑加数似乎更方便? 考虑刚开始在 \(a[1]\) 和 \(a[n]\) 之间加入一个数 \(x\), 会产生 \(2 x\) 的贡献, 如果再在 \(x\) 和 \(a[n]\) 之间插入一个数 \(y\) 呢? 会产生 \(3y\) 的贡献! 这启发我们可以给每个数带一个系数, 枚举在两个数之间插入哪个数, 插入的数的系数就是两边的数的系数相加。
考虑这道题 \(n \leq 18\), 肯定乱搞随便过, 但我们还是证明一下, 考虑每个区间被遍历了一次, 所以时间复杂度 \(O(2^n)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 20;
int a[N], n;
int dp(int l, int r, int xl, int xr) {
if(r - l <= 1) return 0;
int mn = 1e18;
for(int k = l + 1; k < r; k++)
mn = min(mn, dp(l, k, xl, xl + xr) + dp(k, r, xl + xr, xr) + a[k] * (xl + xr));
return mn;
}
signed main() {
scanf("%lld", &n);
for(int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
printf("%lld\n", dp(1, n, 1, 1) + a[1] + a[n]);
return 0;
}