1. 程式人生 > 其它 >AtCoder Beginner Contest 250 G,H

AtCoder Beginner Contest 250 G,H

G

法1:
我們有一種顯然的貪心思路——對於一個\(i\),嘗試找到後面一個\(j\),滿足\(P_{j}>P_{i}\),在\(i\)時刻買入,在\(j\)時刻賣出。

這樣的做法顯然不對。

假設我們是在\(i\)時買入一個stonk,在\(j\)時賣出,而在\(k\)時賣出是最優解。那麼我們可以假設在\(j\)時刻賣出後,我們立刻以\(j\)的價格“嘗試”買入,然後在\(k\)時刻,發現前面有\(j\)時刻的stonk,則總價值為\(p_{j}-p_{i}+p_{k}-p_{j}\),那麼和\(i\)時買入\(k\)時賣出是沒有差異的。

我們使用堆去維護,對於\(i\)\(1\)\(n\)

,我們找到堆中最小的元素,如果它小於\(p_{i}\),那麼我們暫且賣出它,並將\(p_{i}\)加入佇列中。最後,我們還需要把\(p_{i}\)本身加入。

法2:
假設\(a_{i}=1\)表示我們在\(i\)時刻買入stonk,\(a_{i}=-1\)表示我們在\(i\)時刻賣出stonk,\(a_{i}=0\)表示我們什麼都不做。

那麼我們的字首和\(sum_{i}=\sum_{j=0}^{i} a_{j}\)必須要滿足\(sum_{i}>0\)

開始我們假設所有點都是\(a_{i}=1\)

從大往小考慮\(p_{i}\):若我們選擇在\(i\)時刻賣出,那麼\(sum_{i},sum_{i+1},...\)

都要減去\(2\);若我們在\(i\)時刻什麼都不做,那麼\(sum_{i},sum_{i+1},...\)都要減去\(1\);否則維持原樣,\(sum_{i}\)也不改變。

我們肯定儘可能將更多的點改為\(-1\),其次是\(0\)。所以對於\(\min_{j=i}^{n} sum_{j}\geq 2\)時,我們肯定選擇在\(i\)時刻賣出;對於\(\min_{j=i}^{n} sum_{j}=1\)時,我們選擇什麼都不做;否則我們選擇維持原樣。

這可以使用線段樹實現。