HDU多校第六場 1007 Getting Your Money Back —— DP + 單調優化

題目鏈接:點我啊╭(╯^╰)╮

題目大意:

    你的銀行賬戶餘額在 [x,y][x,y] 範圍內
    你需要把它全部取出來,若取 xx
    若當前餘額 x≥x,則耗費 aa 元取出 xx
    若當前餘額 x<x,則耗費 bb 元,取出失敗
    問全取出最壞情況下的最低耗費

解題思路:

    假設 a==ba == b,那麼很明顯是二分
    每次取中點,這樣一定最貪心
    問題在於 aba ≠ b,那麼中點就不一定是最貪心的
    所以要枚舉中間每一個點


    發現答案與區間長度 yxy-x 有關,與 [x,y][x,y] 無關
    但是發現 x=0x = 0 時,當我們取到 11 時,無論成功失敗,00 都不需要再取
    如果餘額在 [1,y][1,y] ,當我們取到 22 時,如果失敗,還要取 11
    所以分兩種情況DP:
    dp[i][0]dp[i][0] 表示 左端點爲 00 ,長度爲 ii 的答案, dp[i][1]dp[i][1] 則表示左端點不爲 00
    dp[i][0]=min(max(dp[j1][0]+b,dp[ij][0]+a))dp[i][0] = min( max(dp[j-1][0] + b, dp[i-j][0] + a) )
    dp[i][1]=min(max(dp[j1][1]+b,dp[ij][0]+a))dp[i][1] = min( max(dp[j-1][1] + b, dp[i-j][0] + a) )


    枚舉 jj ,若 jj 失敗,則範圍變爲 [x,j1][x,j-1]
    若 jj 成功,則變爲 [jj,ij]=[0,ij][j-j, i-j] = [0, i-j]

    這樣的 dpdpn2n^2 的,很明顯看出來區間長度越長,答案越大
    也就是 dp[i][0]dp[i][0] 單調不減,那麼 maxmax 裏的函數就是一個單調不增,一個單調不減
    所以 max(dp[j1][0]+b,dp[ij][0]+a)max(dp[j-1][0] + b, dp[i-j][0] + a) ,就是先減後增
    所以對與某一個 ii ,設其決策點爲 jj
    易得對於 i>i 的點,其決策點 jj 只會往後移
    均攤時間複雜度: O(n)O(n)

核心:DP + 單調優化

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int T, x, y, a, b; 
ll dp[maxn][2];

ll slope0(int j, int i){
	return max(dp[j-1][0] + b, dp[i-j][0] + a);
}
ll slope1(int k, int i){
	return max(dp[k-1][1] + b, dp[i-k][0] + a);
}

int main() {
	scanf("%d", &T);
	while(T--){
		scanf("%d%d%d%d", &x, &y, &a, &b);
		int n = y - x;
		dp[0][0] = 0, dp[0][1] = a;
		for(int i=1, j=1, k=1; i<=n; i++){
			while(j<i && slope0(j+1, i) <= slope0(j, i)) j++;
			while(k<i && slope1(k+1, i) <= slope1(k, i)) k++;
			dp[i][0] = slope0(j, i), dp[i][1] = slope1(k, i);
		}
		printf("%lld\n", dp[n][x>0]);
	}
}
發佈了231 篇原創文章 · 獲贊 226 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章