看完題面想了一會發現只會寫$n^3$,愣了一會才想出了單調佇列優化的做法。
90分演算法:
設$f_$表示第$i$分鐘在第$j$座城市已經走了$k$步的最大價值,轉移顯然,時間複雜度$o(n^3)$。
但是我沒有實現它。
100分演算法:
思考一下最終的答案是怎樣選出來的,我們把矩陣畫出來:
發現題目可以轉化為在這個矩陣上選若干個斜對角線,使得每一列都有且僅有乙個被選到,最後獲得的總價值為所有選到的格仔上的值再減去所有斜對角線開始的格仔對應的代價,使這個總價值最大。
設$f_$表示到第$i$分鐘,當前再$j$能選到的最大價值,那麼發現最多只能從$1-p$層上轉移過來。
$f_ = max(max(f_) + calc(i- k, i) - cost_) (1 \leq k \leq p - 1) (1 \leq o \leq n)$
$calc(i, j)$表示這一條對角線(從$i$層到$j$層)上的價值總和,可以通過斜線上預處理字首和得到,$pos(i, j)$表示$i$上移$j$層所到達的縱座標,$cost_$表示在第$i$個城市買機械人的代價。
那麼對每一條斜的對角線維護乙個單調佇列即可。
時間複雜度$o(n^2)$。
我還是沒有實現它。
介紹一種dalao的思路。(第二個id叫ghastlcon)的大佬,他的luogu部落格中這篇文章看不了了……
有乙個小trick就是把下標從$0$到$n - 1$編號,這樣子上面定義的$pos(i, j) = ((i - j) \% n + n) \% n$,這樣子做字首和的時候也比較方便。
其實我們發現$f$的第二維是沒r用的,所以可以直接拿掉,因為在乙個結束的位置並不影響在下乙個開始的位置,我們要的只是這個最大值。
把字首和$g$完整地寫出來,有:$f_ = max(f_ + g_ - g_ - cost_) (1 \leq i - j \leq p - 1)$。
可以把之後與$i$有關的項拿到外面來,就可以用單調佇列優化了。
時間複雜度$o(n^2)$。
code:
#include #includeview codeusing
namespace
std;
const
int n = 1005
;int
n, m, k, a[n], g[n][n], f[n];
inline
void read(int &x)
struct
priqueue
inline
void push(int x, int
val)
inline
void pop(int
p)
} q[n];
inline
int pos(int x, int
len)
inline
void chkmax(int &x, int
y) int
main()
memset(f,
128, sizeof(f)); f[0] = 0
;
for(int i = 1; i <= m; i++)
for(int j = 0; j < n; j++)
}
printf(
"%d\n
", f[m]);
return
0;
}
P1070 道路遊戲
小新正在玩乙個簡單的電腦遊戲。遊戲中有一條環形馬路,馬路上有 n 個機械人工廠,兩個相鄰機械人工廠之間由一小段馬路連線。小新以某個機械人工廠為起點,按順時針順序依次將這 n 個機械人工廠編號為1 n,因為馬路是環形的,所以第 n 個機械人工廠和第 1 個機械人工廠是由一段馬路連線在一起的。小新將連線...
luogu P1070 道路遊戲 DP
luogu p1070 道路遊戲 題目描述 小新正在玩乙個簡單的電腦遊戲。遊戲中有一條環形馬路,馬路上有 n 個機械人工廠,兩個相鄰機械人工廠之間由一小段馬路連線。小新以某個機械人工廠為起點,按順時針順序依次將這 n 個機械人工廠編號為1 n,因為馬路是環形的,所以第 n 個機械人工廠和第 1 個機...
洛谷P1070 道路遊戲
小新正在玩乙個簡單的電腦遊戲。遊戲中有一條環形馬路,馬路上有 n 個機械人工廠,兩個相鄰機械人工廠之間由一小段馬路連線。小新以某個機械人工廠為起點,按順時針順序依次將這 n 個機械人工廠編號為1 n,因為馬路是環形的,所以第 n 個機械人工廠和第 1 個機械人工廠是由一段馬路連線在一起的。小新將連線...