黑板上有n個數字寫成一排,現在每次選擇兩個相鄰的數字,把比較小的那個數字擦掉(如果兩個數字一樣大,那麼擦掉任何一個都可以。)然而,這些步驟需要花費,這個花費恰好等於留下來的那個數字(比較大的那個)。
請問經過n-1次操作,黑板上會剩下的那個數字是多少?
你以為問題這麼簡單嗎?錯!
真正的問題是:
請問經過n-1次操作,黑板上會剩下最大的那個數字,所有操作方法中,最小總花費是多少?
$1\leq n\leq 1,000,000$
如果花費要小 在每次砍數字的時候比較大的那個數字要比較小
換個角度就是在砍掉某個數字時我們要選擇他左右兩邊比較小的那個數字
然後就Linked List就好了
不過我好懶得寫指標型 所以就陣列開下去
複雜度$\mathcal{O}(NlogN)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include <bits/stdc++.h> using namespace std;
typedef int64_t ll; const int INF = 0x3F3F3F3F;
#define int ll int prv[1000000], nxt[1000000], num[1000000];
struct CMP { bool operator() (int a, int b) { return (num[a]>num[b]); } };
signed main() { ios::sync_with_stdio(0); cin.tie(NULL);
int n; ll ans = 0; cin >> n; priority_queue<int, vector<int>, CMP> pq; for(int i = 0; i < n; i++) cin >> num[i]; for(int i = 0; i < n; i++) prv[i]=i-1, nxt[i]=i+1, pq.push(i); prv[0]=nxt[n-1]=-1; while(pq.size()>1) { int now=pq.top(); pq.pop();
int a, b; if(prv[now]==-1) a=INF; else a=num[prv[now]]; if(nxt[now]==-1) b=INF; else b=num[nxt[now]]; ans+=min(a, b);
int pr=prv[now], nx=nxt[now]; if(nx!=-1) prv[nx]=pr; if(pr!=-1) nxt[pr]=nx; } cout << ans;
return 0; }
|