// 51nod 神题 :数据贼大,没法用dp
屠龙宝刀:点击打开链接
解题思路:使用神奇的 GarsiaWachs 算法,
算法:(懒得写了Orz)
它的步骤如下:
设序列是stone[],从左往右,找一个满足stone[k-1] <= stone[k+1]的k,找到后合并stone[k]和stone[k-1],再从当前位置 开始向左找最大的j,使其满足stone[j] > stone[k]+stone[k-1],插到j的后面就行。一直重复,直到只剩下一堆石子就可以了。 在这个过程中,可以假设stone[-1]和stone[n]是正无穷的。
证明参考:
不知为何大佬的代码过不去,我自己也看不懂他的代码,于是乎自己写了个dsf,搞了半天,AC!!
// 51nod 1023
// 18.2.5
// http://blog.csdn.net/acdreamers/article/details/18043897
//于石子合并问题,有一个最好的算法,那就是GarsiaWachs算法。时间复杂度为O(n^2)。
// his time :
// mytime : 1640ms
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bg(x) cout<<(x)<<endl ;
const int N = 50000 ;
const int inf = 0x3f3f3f3f;
int n, a[N], len; // 总长度
ll ans = 0;
void dfs(int p)
{
if(len==1) return ;
int k = p, i, j, ret;
while(k<=len&&a[k-1]>a[k+1]) k++;
ret = a[k-1] + a[k];
ans += ret;
for(i=k;i<=len;i++) a[i] = a[i+1]; //把后面的数字挪过来
for(j=k-2;j>=0&&a[j]<=ret;j--) a[j+1] = a[j]; // 把前面的数移过去
a[j+1] = ret;
len--;
if(j>=3) j -= 2; // 对于新插入的数字 也许会导致 之前序列的的“递减”
//性质改变,所以要多遍历几个数字
dfs(j+1);
}
int main(){
//freopen("test.txt","r",stdin);
scanf("%d",&n);
fill(a,a+n+3,inf);
len = n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
dfs(1);
printf("%lld\n",ans );
}