題目描述:
第1行:N(2 <= N <= 50000) 第2 - N + 1:N堆石子的數量(1 <= A[i] <= 10000)
輸出最小合併代價
4 1 2 3 4
19
具體實現方法:
設一個序列是A[0..n-1],每次尋找最小的一個滿足A[k-1]<=A[k+1]的k,那麼我們就把A[k]與A[k-1]合併,之後從k向前尋找第一個滿足A[j]>A[k]+A[k-1]的j,把合併後的值A[k]+A[k-1]插入A[j]的後面。
代碼如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#define ri(n) scanf("%d",&n)
#define oi(n) printf("%d\n",n)
#define rl(n) scanf("%lld",&n)
#define ol(n) printf("%lld\n",n)
#define rep(i,l,r) for(i=l;i<=r;i++)
#define rep1(i,l,r) for(i=l;i<r;i++)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int epg=10-8;
int a[50000+10];
ll ans;
int t;
void dfs(int k)
{
int tmp=a[k-1]+a[k];
ans+=tmp;
for(int i=k;i<t-1;i++)
a[i]=a[i+1];
t--;
int j;
for(j=k-1;j>0&&a[j-1]<tmp;j--)
a[j]=a[j-1];
a[j]=tmp;
while(j>=2&&a[j]>=a[j-2])
{
int d=t-j;
dfs(j-1);
j=t-d;
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
t=1;
ans=0;
for(int i=1;i<n;i++)
{
a[t++]=a[i];
while(t>=3&&a[t-3]<=a[t-1])
dfs(t-2);
}
while(t>1)
dfs(t-1);
printf("%lld\n",ans);
return 0;
}