乍一看很激动(诶辣鸡题才做过)然后n=4e4+o(n^3)=GG
GarsiaWachs算法
或者四边形优化(还是GG不用搞了)(以后自己写一遍)
还可以加上个平衡树(憋说了……)
step 0:初始数组为num[1..n],num[0] = num[n+1] = INF
step 1:每次找到一个最小的i使得num[i-1]<=num[i+1],将num[i-1]和num[i]合并为temp
step 2:找到前面一个最大的j使得num[j]>temp,将temp放在j之后。
step 3:重复1,2,直到剩余的堆数为1。
因为每次step2之后,指向的位置只需要向前一个即可(前面其他的都不会受到此次更新的影响),因此每次指针的移动并不多。也因此,一个理论复杂度其实有O(N^2)的算法能够轻松过掉这道题。
//GarsiaWachs
/*设序列是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]是正无穷的。*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=5e4+5;
int n,t,ans,stone[N];
void combine(int k)
{
int tmp=stone[k]+stone[k-1];//合并
ans+=tmp;
for(int i=k;i<t-1;i++)
stone[i]=stone[i+1];//左移
t--;
int j=0;
for(j=k-1;j>0&&stone[j-1]<tmp;j--)
stone[j]=stone[j-1];
stone[j]=tmp;//插入到j后面
while(j>=2&&stone[j]>=stone[j-2])
{
int d=t-j;
combine(j-1);
j=t-d;
}
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d",&n)!=EOF&&n)
{
for(int i=0;i<n;i++)
scanf("%d",stone+i);
t=1;
ans=0;
for(int i=1;i<n;i++)
{
stone[t++]=stone[i];
while(t>=3&&stone[t-3]<=stone[t-1])
combine(t-2);
}
while(t>1)combine(t-1);
printf("%d\n",ans);
}
return 0;
}
因篇幅问题不能全部显示,请点此查看更多更全内容