在一个操场上摆放着一排 N N N 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的 2 2 2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
试设计一个算法,计算出将 N N N 堆石子合并成一堆的最小得分。
第一行一个整数 N N N。
接下来 N N N 行,第 i i i 行一个整数 a i a_i ai,代表第 i i i 堆石子的石子数。
输出将所有石子合并为一堆的最小得分。
4
1
1
1
1
8
$ N \leq 40000, a_i \leq 200$
请注意 N N N 的范围
设一个序列是A[0…n-1],
每次寻找最小的一个满足A[k-1]<=A[k+1]的k,
那么我们就把A[k]与A[k-1]合并,
ans += (A[k]+A[k-1])
之后从k向前寻找第一个满足A[j]>A[k]+A[k-1]的j,
把合并后的值A[k]+A[k-1]插入A[j]的后面。
#include <bits/stdc++.h>
#define buff \
ios::sync_with_stdio(false); \
cin.tie(0);
//#define int long long
using namespace std;
const int N = 1000;
int n;
vector<int> s;
int func()
{
int idx = s.size() - 2;
for (int i = 0; i < s.size() - 2; i++)
{
if (s[i] <= s[i + 2])
{
idx = i;
break;
}
}
int tt = s[idx] + s[idx + 1];
s.erase(s.begin() + idx);
s.erase(s.begin() + idx);
int idx2 = -1;
for (int i = idx - 1; i >= 0; i--)
{
if (s[i] > tt)
{
idx2 = i;
break;
}
}
s.insert(s.begin() + idx2 + 1, tt);
return tt;
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
int t;
cin >> t;
s.push_back(t);
}
int ans = 0;
for (int i = 1; i < n; i++)
ans += func();
cout << ans << '\n';
}
int main()
{
buff;
solve();
}
/*
设一个序列是A[0..n-1],
每次寻找最小的一个满足A[k-1]<=A[k+1]的k,
那么我们就把A[k]与A[k-1]合并,
ans += (A[k]+A[k-1])
之后从k向前寻找第一个满足A[j]>A[k]+A[k-1]的j,
把合并后的值A[k]+A[k-1]插入A[j]的后面。
*/