1. 程式人生 > >【NOIP2018】D1T1 鋪設道路

【NOIP2018】D1T1 鋪設道路

@鋪設道路@


@題目描述@

春春是一名道路工程師,負責鋪設一條長度為 n 的道路。
鋪設道路的主要工作是填平下陷的地表。整段道路可以看作是 n 塊首尾相連的區域,一開始,第 i 塊區域下陷的深度為 di。

春春每天可以選擇一段連續區間 [L,R],填充這段區間中的每塊區域,讓其下陷深度減少 1。在選擇區間時,需要保證,區間內的每塊區域在填充前下陷深度均不為 0$。

春春希望你能幫他設計一種方案,可以在最短的時間內將整段道路的下陷深度都變為 0 。

輸入
輸入檔案包含兩行,第一行包含一個整數 n,表示道路的長度。 第二行包含 n 個整數,相鄰兩數間用一個空格隔開,第 i 個整數為 di。

輸出
輸出檔案僅包含一個整數,即最少需要多少天才能完成任務。

輸入樣例#1:
6
4 3 2 5 3 5
輸出樣例#1:
9

樣例解釋1:
一種可行的最佳方案是,依次選擇: [1,6]、[1,6]、[1,2]、[1,1]、[4,6]、[4,4]、[4,4]、[6,6]、[6,6]。

資料規模與約定
對於 30% 的資料,1 ≤ n ≤ 10;
對於 70% 的資料,1 ≤ n ≤ 1000;
對於 100% 的資料,1 ≤ n ≤ 100000 , 0 ≤ di ≤ 10000。

@考場上的思路@

我 抄 我 自 己?
雖然這是 NOIP2013 的原題“積木遊戲”……然而我並沒有做過-_-
所以考場上想了一個比較複雜的解:
顯然觀察樣例,我們可以貪心地這樣做:對於某一個區間,選擇最小值,將這個區間減去這個最小值,然後把區間按照這個最小值分為兩個區間分治求解。
因此,本來想寫線段樹來著……但是我及時地發現(其實是因為不想寫再多想會兒hhhh)區間的最小值是不會變化的。也就是說我們可以不去動態查詢區間最小值,而是建成笛卡爾樹,再在笛卡爾樹上進行操作。

程式碼(不建議參考,建議繼續往後看正常的解):

#include<cstdio>
#include
<stack>
using namespace std; typedef long long ll; const int MAXN = 100000; const int MAXD = 10000; struct node{ ll ans; int d; node *ch[2]; }tree[MAXN + 5], *tcnt, *NIL, *root; void init() { root = NIL = tcnt = &tree[0]; NIL->ch[0] = NIL->ch[1] = NIL; } node *newnode(int d) { tcnt++; tcnt->d = d; tcnt->ch[0] = tcnt->ch[1] = NIL; return tcnt; } stack<node*>stk; int d[MAXN + 5]; void dfs(node *rt, int x) { if( rt == NIL ) return ; dfs(rt->ch[0], rt->d); dfs(rt->ch[1], rt->d); rt->ans = rt->ch[0]->ans + rt->ch[1]->ans + (rt->d - x); } int main() { init(); int n; scanf("%d", &n); for(int i=1;i<=n;i++) scanf("%d", &d[i]); for(int i=1;i<=n;i++) { node *nw = newnode(d[i]), *lst = NIL; while( !stk.empty() && stk.top()->d > nw->d ) { lst = stk.top(); stk.pop(); } if( !stk.empty() ) stk.top()->ch[1] = nw; nw->ch[0] = lst; stk.push(nw); } while( !stk.empty() ) { root = stk.top(); stk.pop(); } dfs(root, 0); printf("%lld\n", root->ans); return 0; }

@比較正常的題解@

我們實際上是求如圖的塊的個數。
解釋圖
我們不妨在塊的右端點去統計每一塊對答案的貢獻。
所以就很簡單了:
(1)如果 d[i] >= d[i+1],則 ans+=(d[i]-d[i+1])
(2)如果 d[i] < d[i+1],則 continue
最後 ans+= d[n] 即可

#include<cstdio>
typedef long long ll;
const int MAXN = 100000;
int d[MAXN + 5];
int main() {
    int n; ll ans = 0;
    scanf("%d", &n);
    for(int i=1;i<=n;i++)
        scanf("%d", &d[i]);
    for(int i=1;i<n;i++)
    	if( d[i] >= d[i+1] ) ans += d[i] - d[i+1];
    ans += d[n];
    printf("%lld\n", ans);
}

@[email protected]

就是這樣,新的一天裡,也請多多關照哦(ノω<。)ノ))☆.。