洛谷P1776 寶物篩選
阿新 • • 發佈:2018-09-14
篩選 習慣 結構體 space 價格 out name 處理 bits \(f[i][j]=max\{f[i-1][j-k*v[i]]+k*w[i]\},j-k*v[i]\geqslant 0\)
但這樣時間復雜度太高了,令\(r=j\%v[i],s=\left \lfloor \frac{j}{v[i]} \right \rfloor\)考慮給轉移方程變形為:
\(f[i][j]=max\{f[i-1][r+k*v[i]]-k*w[i]\}+s*w[i],s-c[i]\leqslant k\leqslant s\)
這個轉移方程同樣是正確的,並且我們發現取\(max\)的那一部分,在\(r\)確定的情況下,只跟\(k\)的值有關,於是我們就可以用單調隊列優化啦。枚舉\(i\),\(r\)之後,對於每一個\(r\)我們開一個單調隊列,掃一遍就好了
時間復雜度\(O(nV)\)
坑點:重量為\(0\)的物品要直接累加到答案中!
代碼如下(懶得用滾動數組):
一道很好的單調隊列優化多重背包入門題
令\(v[i]\)表示重量,\(w[i]\)表示價格 ,\(c[i]\)表示最多可放的數量,不難推出樸素的轉移方程如下:
但這樣時間復雜度太高了,令\(r=j\%v[i],s=\left \lfloor \frac{j}{v[i]} \right \rfloor\)考慮給轉移方程變形為:
這個轉移方程同樣是正確的,並且我們發現取\(max\)的那一部分,在\(r\)確定的情況下,只跟\(k\)的值有關,於是我們就可以用單調隊列優化啦。枚舉\(i\),\(r\)之後,對於每一個\(r\)我們開一個單調隊列,掃一遍就好了
時間復雜度\(O(nV)\)
坑點:重量為\(0\)的物品要直接累加到答案中!
代碼如下(懶得用滾動數組):
#include <bits/stdc++.h> using namespace std; int n, m, zero, v[(int)1e5], w[(int)1e5], c[(int)1e5], f[105][(int)2e5]; struct S { //習慣開結構體QwQ int id, w; }q[(int)2e5]; int main() { cin >> n >> m; for(int i = 1; i <= n; ++i) cin >> w[i] >> v[i] >> c[i]; for(int i = 1; i <= n; ++i) { if(!v[i]) { //處理重量為0的物品 zero += w[i]*c[i]; continue; } for(int r = 0, h = 0, t = 0; r < v[i]; ++r, h = t = 0) //h,t記得清零 for(int j = r, s = 0; j <= m; j += v[i], ++s) { while(h < t && q[t-1].w < f[i-1][j]-s*w[i]) --t; //--維護 q[t++] = S{s, f[i-1][j]-s*w[i]}; //--隊列 while(h < t && q[h].id < s-c[i]) ++h; //--單調性 f[i][j] = q[h].w+s*w[i]; } } cout << zero+f[n][m]; return 0; }
洛谷P1776 寶物篩選