这题就是P1775石子合并的数据加强版,我们那题采用的是区间DP,时间复杂度为O(n3) (4*1e4)的三次方=1.6*1e13,显然超时。这里就必须用一个算法,叫做GarsiaWachs算法,可以降低时间复杂度至n2甚至nlogn.
GarsiaWachs算法:他的做法就是对于一个序列a,先int ans=0,然后从左到右找到a[k-1]<a[k+1],将a[k]和a[k-1]合并成一个新的元素a[temp],从a[k-1]向左寻找,找到第一个比他大的,插入在他后面,ans+=a[temp],注意要把a[-1]和a[终点]定义为无穷大,方便寻找插入。然后再重复这个操作,直到序列中没有a[k-1]<a[k+1].原理我也不会推导,只知道这么个结论。
这是我的代码:利用stl来操作,但是要开O2优化,否则只有70分,T3个点。
1 //GarsiaWachs 2 //开O2 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 #include<vector> 7 #include<climits>//INT_MAX的头文件 8 using namespace std; 9 int read() 10 { 11 int f = 1; 12 int ans = 0; 13 char c = getchar(); 14 if (c > '9' || c < '0') 15 { 16 f = -1; 17 c = getchar(); 18 } 19 while (c >= '0' && c <= '9') 20 { 21 ans = (ans << 1) + (ans << 3) + (c - '0'); 22 c = getchar(); 23 } 24 return f * ans; 25 } 26 int main() 27 { 28 int n; 29 n = read(); 30 vector<int>v; 31 v.push_back(INT_MAX - 1); 32 for (int i = 1; i <= n; ++i) 33 { 34 v.push_back(read()); 35 } 36 v.push_back(INT_MAX); 37 int k, j, temp, sum = 0; 38 while (n-- > 1) 39 { 40 for (k = 1; k <= n; ++k) 41 { 42 if (v[k - 1] < v[k + 1]) 43 break; 44 } 45 temp = v[k - 1] + v[k]; 46 for (j = k - 1; j >= 0; --j) 47 { 48 if (v[j] > temp) 49 break; 50 } 51 v.erase(v.begin() + k - 1);//删掉k-1; 52 v.erase(v.begin() + k - 1);//删掉k 53 v.insert(v.begin() + j + 1, temp);//插入和 54 sum += temp; 55 } 56 cout << sum; 57 return 0; 58 59 }
没开O2:
开O2:
最后补充一下:这个GarsiaWachs算法的标准代码模板,时间复杂度也特别低,高效通过,但是我看了很久也理解不了他的原理。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=50005; 4 5 int n; 6 int a[maxn]; 7 int num; 8 int ans; 9 10 void combine(int k){ 11 12 int temp=a[k]+a[k-1]; 13 ans+=temp; 14 for (int i=k;i<num-1;i++){ 15 a[i]=a[i+1]; 16 } 17 num--; 18 19 int j=0; 20 for (j=k-1;j>0&&a[j-1]<temp;j--){ 21 a[j]=a[j-1]; 22 } 23 a[j]=temp; 24 25 while (j>=2&&a[j]>=a[j-2]){ 26 int d=num-j; 27 combine(j-1); 28 j=num-d; 29 } 30 } 31 32 int main() 33 { 34 cin >> n; 35 for (int i=0;i<n;i++){ 36 cin >> a[i]; 37 } 38 num=1; 39 ans=0; 40 for (int i=1;i<n;i++){ 41 a[num++]=a[i]; 42 while (num>=3&&a[num-3]<=a[num-1]){ 43 combine(num-2); 44 } 45 } 46 while (num>1){ 47 combine(num-1); 48 } 49 50 cout << ans << endl; 51 }