$Link$
有 $n$ 张卡片排成一排,上面写有数字 $a_{1\cdots n}$。你每次可以选择相邻的三张卡片,去掉中间那张并把它上面的数字分别加到另两张上。求最后剩下的两个数字的和的最小值。
$2\le n\le18$。
·
考虑枚举一段区间最后选的数,把一段区间分成两段区间然后分治解决。
我们设该区间左端点最后对答案贡献 $lx$ 次,右端点 $rx$ 次。那我们选的这个数最后对答案的贡献就是 $lx+rx$ 次。而分出来的左区间的右端点和右区间的左端点的贡献就是 $lx+rx$。
暴力 $dp$ 即可,时间复杂度不知道。
$code$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include <iostream> #include <cstdlib> #include <cstdio> #define ll long long using namespace std; inline int read() { int f = 1, x = 0; char ch;
do{ ch = getchar(); if (ch == '-') f = -1; }while(ch < '0' || ch > '9'); do{ x = x * 10 + ch - '0'; ch = getchar(); }while(ch >= '0' && ch <= '9'); return f * x; } const int N = 18;
int n; int a[N + 1];
inline ll dfs(int l, int r, int lx, int rx) { if (r - l + 1 <= 2) return 0; ll ans = 1e18;
for (int i = l + 1; i <= r - 1; i++) ans = min(ans, dfs(l, i, lx, lx + rx) + dfs(i, r, lx + rx, rx) + 1ll * (lx + rx) * a[i]); return ans; } int main() { n = read(); for (int i = 1; i <= n; i++) a[i] = read();
printf("%lld\n", a[1] + a[n] + dfs(1, n, 1, 1));
return 0; }
|