1. 程式人生 > >BZOJ1345 Baltic2007 序列問題Sequence 【思維題】*

BZOJ1345 Baltic2007 序列問題Sequence 【思維題】*

BZOJ1345 Baltic2007 序列問題Sequence

Description

對於一個給定的序列a1,…,an,我們對它進行一個操作reduce(i),該操作將數列中的元素ai和ai+1用一個元素max(ai,ai+1)替代,這樣得到一個比原來序列短的新序列。這一操作的代價是max(ai,ai+1)。進行n-1次該操作後,可以得到一個長度為1的序列。我們的任務是計算代價最小的reduce操作步驟,將給定的序列變成長度為1的序列。

Input

第一行為一個整數n( 1 <= n <= 1,000,000 ),表示給定序列的長度。 接下來的n行,每行一個整數ai(0 <=ai<= 1, 000, 000, 000),為序列中的元素。

Output

只有一行,為一個整數,即將序列變成一個元素的最小代價。

Sample Input

3 1 2 3

Sample Output

5

其實這題比較思維

考慮一個數的貢獻

如果他比左/右邊的數大,則一定會產生這個數的貢獻,並且左右邊分別計算

來想想這是為啥,我們只先考慮一邊(左邊)的情況

如果這個數比左邊的數小,那麼無論如何這個數不會產生貢獻

如果它比左邊的數大,那麼考慮這個情況 將情況化簡成a,b,c三個數,其中我們在對c進行討論

那麼如果a<c,c一定會有c的貢獻 如果a>c,這時候我們考慮先合併a,b還是b,c,最後合併a,c的貢獻是定值,合併b,c的貢獻顯然比合並a,b要優秀,所以肯定會先合併b,c,這裡產生了c的貢獻

所以前面的結論我們證明了

#include<bits/stdc++.h>
using namespace std;
#define N 1000010
int a[N],n;
long long ans=0;
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++)scanf("%d",&a[i]);
  for(int i=2;i<=n;i++)ans+=max(a[i],a[i-1]);
  printf("%lld",ans);
  return 0;
}