题解 P5569 【[SDOI2008]石子合并】

jyz666

2020-08-04 21:21:26

Solution

# 题解 P5569 【[SDOI2008]石子合并】 [传送门](https://www.luogu.com.cn/problem/P5569) 这题一开始一看,还以为是双倍经验。。 写一个普通dp。 AC:3 RE:7 仔细一看是一个加强版,N<=40000 啊这。。。 费(kan)尽(le)心(ti)思(jie),才知道原来这道题要用GarsiaWachs算法。 这个算法简述来说就是:加入有$a,b,c$三个石子堆 先合并左边两个的代价是$2a+2b+c$,而先合并右边两个的代价是$a+2b+2c$,所以只用看$a$和$c$,$a<c$ 于是先合并$a<c$的吧,完了之后如果还有剩就从右边开始合并$bc$ 合并$ab$的时候,合并之后插入从左边数第一个大于他的数的后面开始,究竟为什么这么做我也不怎么理解。。。 但是如果这道题就这样按照所说的话会$TLE$ ,因为插入删除都是$O(n)$的,所以只好想个办法让这个$n$变得比较小 新开了一个数组,一个一个加石头进去,满足$a b$的合并条件就合并,这样会保持$n$比较小 ### 上代码》》 ```cpp #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<iostream> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double db; #define maxn 50010 #define inf 0x3f3f3f3f const int mod=100003; void read(int &x){ int f=1;x=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} x*=f; } int n,w; long long ans=0; vector<int> l; int solu(){ int k=l.size()-2,q=-1; for(int i=0;i<l.size()-2;++i) if (l[i]<=l[i+2]) {k=i;break;} int t=l[k]+l[k+1]; l.erase(l.begin()+k);l.erase(l.begin()+k); for(int i=k-1;i>=0;--i) if (l[i]>t) {q=i; break;} l.insert(l.begin()+q+1,t); return t; } int main(){ read(n); for(int i=1;i<=n;++i) read(w),l.push_back(w); for(int i=0;i<n-1;i++) ans+=solu(); printf("%lld",ans); return 0; } ``` ### _勝負は時の運、と言うでしょ?_