1. 程式人生 > >單調佇列優化多重揹包

單調佇列優化多重揹包

演算法

應該是個經典演算法,稍微記錄一下

\(w[i]\)表示重量,\(v[i]\)表示價值

那麼不難寫出轉移方程

\(f[i][j] = max(f[i - 1][j - k * w[i]] + k * v[i])\)

考慮用單調佇列優化。

我們若要用單調佇列優化,那麼必須滿足轉移時所需要的狀態只與\(k\)有關

這裡要用到一個神仙操作,對\(j \% w[i]\)分類

因為對於\(\% j\)後相同的數,轉移時只有\(k\)的值不相同。

\(a = \frac{j}{w[i]}, b = j \% w[i]\)

那麼轉移方程可以寫成

\(f[i][j] = max(f[i - 1][b + k * w[i]] - k * v[i]]) + a * v[i]\)

對每個\(j \% w[i]\)分別維護單調佇列即可。。

同時\(f\)陣列可以滾動一下

程式碼

題目連結

#include<bits/stdc++.h>
#define LL long long 
using namespace std;
const int MAXN = 1001;
inline int read() {
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M, C, q[10001];
LL f[10001], val[10001];
main() {
    N = read(); M = read(); C = read();
    for(int i = 1; i<= N; i++) {
        int w = read(), v = read(), d = read();
        for(int b = 0; b < w; b++) {//b = j % w  原體積為j = k * w + b
            for(int k = 0, h = 1, t = 0, j = b; j <= C; k++, j += w) {
                int a = k * v, tmp = f[j] - a;// a = j / w * v = k * v
                while(h <= t && tmp > val[q[t]]) t--;
                q[++t] = k; val[q[t]] = tmp;//由於這裡的val需要被更新過後才能使用,因此不用清空
                while(h <= t && q[h] + d < k) h++;//需要的物品超過d個
                f[j] = val[q[h]] + a;
            }
        }
    }
    for(int i = 1; i <= M; i++) {
        int a = read(), b = read(), c = read();//
        for(int j = C; j >= 0; j--)//列舉一下體積
            for(int k = 0; k <= j; k++)
                f[j] = max(f[j], f[j - k] + (a * k + b) * k + c);
    }
    cout << f[C];
    return 0;
}

相關推薦

codevs5429(單調佇列優化多重揹包)

其實這個知識點並不是很難。。只是覺得並不會這麼極限卡log就沒去管他。。直到今天差點被卡TAT 稍微推導一下 設d[i][j]為前i種物品體積為j的最大價值 此時 令,,有 此時即 然後考慮到列舉k的時候k一定為整數,所以直接就行。。然後發現這就是劃窗。。

揹包問題入門(單調佇列優化多重揹包

揹包問題 寫這篇文章主要是為了幫幫新人吧,dalao勿噴.qwq 一般的揹包問題問法  每種物品都有一個價值w和體積c.//這個就是下面的變數名,請看清再往下看.  你現在有一個揹包容積為V,你想用一些物品裝揹包使得物品總價值最大. 01揹包   多種物品,每種物品只有一個.求能獲得的最大總價值.  我們考慮

單調佇列優化多重揹包

演算法 應該是個經典演算法,稍微記錄一下 用\(w[i]\)表示重量,\(v[i]\)表示價值 那麼不難寫出轉移方程 \(f[i][j] = max(f[i - 1][j - k * w[i]] + k * v[i])\) 考慮用單調佇列優化。 我們若要用單調佇列優化,那麼必須滿足轉移時所需要的狀態只與\(k

單調佇列優化揹包問題

對於揹包問題,經典的揹包九講已經講的很明白了,本來就不打算寫這方面問題了。 但是吧。。。。。 我發現,那個最出名的九講竟然沒寫佇列優化的揹包。。。。 那我必須寫一下咯嘿嘿,這麼好的思想。 我們回顧一下揹包問題吧。 01揹包問題  題目  有N件物品和

POJ 1276 多重揹包+多重揹包可行化問題+單調佇列優化

A Bank plans to install a machine for cash withdrawal. The machine is able to deliver appropriate @ bills for a requested cash amount. The machine use

揹包模板(01,完全,多重揹包的二進位制優化單調佇列優化

揹包問題 1,01揹包 揹包問題的基礎,總體積為V的揹包,有n件體積v【i】,價值w【i】的物品,求能裝物品的最大總價值 void zero(int v,int w) { for(int j=V;j>=v;j--) { dp[j]=max(dp[j],dp[j

動態規劃的單調佇列優化(含多重揹包

什麼是單調佇列 單調佇列就是元素單調的佇列,譬如一個佇列中的元素為1,2,3,4,5,6,單調遞增,這就是一個單調佇列。咱們先看一道單調佇列的模板題:poj2823/洛谷P1886 怎麼維護單調佇列呢?譬如維護一個單調遞增的佇列,就是要進入一個元素的時候,把

2018.10.29 bzoj1023: [SHOI2008]cactus仙人掌圖(仙人掌+單調佇列優化dp)

傳送門 求仙人掌的直徑。 感覺不是很難。 分點在環上面和不在環上分類討論。 不在環上直接樹形 d p

P3084 [USACO13OPEN]照片Photo (dp+單調佇列優化

題目連結:傳送門 題目: 題目描述 Farmer John has decided to assemble a panoramic photo of a lineup of his N cows (1 <= N <= 200,000), which, as always

HDU 3401 Trade(DP + 單調佇列優化

任重而道遠 Recently, lxhgww is addicted to stock, he finds some regular patterns after a few days' study. He forecasts the next T days' stock market. On

CF939F Cutlet (單調佇列優化DP)

題目大意:要煎一塊有兩個面的肉,只能在一段k不相交的時間段$[l_{i},r_{i}]$內翻轉,求$2*n$秒後,保證兩個面煎的時間一樣長時,需要最少的翻轉次數,$n<=100000$,$k<=100$ 神仙單調佇列優化$DP$, [NOI2005]瑰麗華爾茲 也有類似的壓時間段的套路,但這道題

11.3清北集訓T1work_dp+單調佇列優化

solution subtask1 暴力dp O(nk) #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #incl

[BZOJ1233][Usaco2009Open]乾草堆tower(單調佇列優化

傳送門 題意搞skr人…,其實就是堆方塊: 有n(n<=100000)個乾草,每堆有個寬度,現在要且分成若干段,把每一段的乾草按順序堆起來形成一個多層的乾草堆(所以下標越小的乾草堆放在越下面)且寬度要逐層非嚴格遞減(上面一層的寬度<=下面一層的寬度),求最多可以放多少層。

[USACO18JAN]Lifeguards P 洛谷黑題,單調佇列優化DP

傳送門:戳我 這道題有兩個版本,S和P,S是K等於1的情況,顯然可以用線段樹水過。 P版本就難了很多,洛谷黑題(NOI/NOI+/CTSC),嘿嘿。 我自己也不是很理解,照著題解寫了一遍,然後悟到了一點東西。 dp方程很好想: dp[i][j]表示處理到第i個元素,已經刪掉了j個,但取了第i個。

HDU 3401 Trade(dp+單調佇列優化

Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5843  &

POJ - 2823 Sliding Window【單調佇列優化dp && c++快讀】

Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 72718 &nb

乾草堆[單調佇列優化DP]

傳送門 f[i] 表示到第i個時,第i個下面的乾草的寬度 很明顯寬度越窄,高度越高 需滿足 也就是 我們發現,對於k>j>i,若 則j比k優 #include<bits/stdc++.h> #define N 10000

股票交易[單調佇列優化DP]

傳送門 我們用f[i][j] 表示交易到第i天,手上有j個股票的最大收益 對於買入 變一下形 單調佇列維護min中的一坨就可以了 #include<bits/stdc++.h> #define N 5005 using namespace std; i

Dividing the Path POJ - 2373 詳細題解 (線性DP + 單調佇列優化)

這道題目是一道較為複雜的線性Dp題目, 我會按照思路詳細列舉一些本題解題過程 按照動態規劃問題的一般解題思路來, 首先, 我們需要定義一個狀態dp[i] 表示恰好到覆蓋到 [0, i]時最少需要的噴水裝置數量, 答案自然也就是dp[L], 把長度作為容量, 是線性Dp的一種常見方案 然

Luogu 2569 [SCOI2010]股票交易 (樸素動規轉移 + 單調佇列優化)

題意: 已知未來 N 天的股票走勢,第 i 天最多買進 as [ i ] 股每股 ap [ i ] 元,最多賣出 bs [ i ] 股每股 bp [ i ] 元,且每天最多擁有 Mp 股,且每兩次交易至少需要相隔 W 天,求最多能賺多少錢。 細節: 1、初始情況下有無限的資金,但是不能算