1. 程式人生 > >[Vijos1617] 超級教主(DP + 單調隊列)

[Vijos1617] 超級教主(DP + 單調隊列)

amp log pan view alt open 說明 tar 超時

傳送門

設 f[i] 表示吃完 f[i] 及其以下的能量球後所剩下的能量。

所以 f[i] = max(f[i], f[j] + (sum[i] - sum[j]) - i * 100) ( 0 <= j < i )

但這是 O(n2) 的,肯定超時,

把上面的式子變換以下得到 f[i] = max(f[i], (f[j] - sum[j]) + sum[i] - i * 100) ( 0 <= j < i )

也就是說,f[i] 只與 f[j] - sum[j] 有關,sum[i] - i * 100 可看做常數,

要想使 f[i] 最大,需要讓 f[j] - sum[j] 最大,

可用單調隊列維護最大 f[j] - sum[j],

如果 f[q[h]] < i * 100 說明能量不夠跳到當前點,而能量跳不到當前點肯定也跳不到後面的點,h++

——代碼

技術分享
 1 #include <cstdio>
 2 
 3 const int MAXN = 2000001;
 4 int n, m, h = 1, t;
 5 int sum[MAXN], q[MAXN], f[MAXN];
 6 
 7 int main()
 8 {
 9     int i, j, x;
10     scanf("%d %d", &n, &f[0
]); 11 for(i = 1; i <= n; i++) 12 { 13 scanf("%d", &x); 14 sum[i] = x + sum[i - 1]; 15 } 16 t++; 17 for(i = 1; i <= n; i++) 18 { 19 while(h <= t && f[q[h]] < i * 100) h++; 20 f[i] = f[q[h]] - sum[q[h]] + sum[i] - i * 100
; 21 while(h <= t && f[q[t]] - sum[q[t]] < f[i] - sum[i]) t--; 22 q[++t] = i; 23 } 24 printf("%d", f[n]); 25 return 0; 26 }
View Code

[Vijos1617] 超級教主(DP + 單調隊列)