合併石子--Garsia-Wachs貪心
阿新 • • 發佈:2018-12-12
題意:
有n堆石子,每次可以合併相鄰兩個石子,代價為兩堆石子的和,求將這堆石子合併為一堆的最小代價。
這道題可以用平衡樹做,只是維護的東西很多很多,會非常難受
所以我就退而求其次,選擇了ZJC大爺的卡常做法
1e5的資料範圍也能在1s內輕鬆卡過啦!!!
思路與Garsia-Wachs演算法一致
程式碼如下
#include<bits/stdc++.h> using namespace std; unsigned int tot; unsigned long long a[500005]; int n; int read() { char c; int x; for(c=getchar();c!='-'&&(c>'9'||c<'0');c=getchar()); if(c=='-') { x=0; for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; return -x; } else { x=c-'0'; for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; return x; } } unsigned long long ans; void unionn(const unsigned int x) { unsigned int i,j,d; unsigned long long tmp=a[x]+a[x-1]; ans+=tmp; for(i=x;i<tot;++i) a[i]=a[i+1]; tot--; for(j=x-1;a[j-1]<tmp&&j>1;--j) a[j]=a[j-1]; a[j]=tmp; for(d=tot-j;j>2&&a[j-2]<=a[j];d=tot-j) { unionn(j-1); j=tot-d; } } int main() { freopen("mmm.in","r",stdin); freopen("mmm.out","w",stdout); cin>>n; for(register unsigned int i=1;i<=n;i++) a[i]=read(); for(register unsigned int i=1;i<=n;++i) { a[++tot]=a[i]; while(tot>2&&a[tot-2]<=a[tot]) unionn(tot-1); } while(tot>1) unionn(tot); cout<<ans<<endl; return 0; } /* 5 186 64 35 32 103 */