HNOI2007 夢幻島寶珠 DP 折半

2021-09-05 09:57:08 字數 1559 閱讀 7653

description

給你n顆寶石,每顆寶石都有重量和價值。要你從這些寶石中選取一些寶石,保證總重量不超過w,並輸出最大的總價值。

sample input

4 10

8 95 8

4 62 5

4 13

8 95 8

4 62 5

16 75594681

393216 5533

2 77

32768 467

29360128 407840

112 68

24576 372

768 60

33554432 466099

16384 318

33554432 466090

2048 111

24576 350

9216 216

12582912 174768

16384 295

1024 76

-1 -1

sample output

1419

1050650

我們考慮折半一下。

將b大於15次方的數變成a∗2

b−

16a*2^

a∗2b−1

6,然後折半去做dp。

我們發現這樣空間和時間都會炸鍋。

於是我們可以調整一下折半的分界線,我調到10就過了。(感覺我是卡過去的)

#include #include #include #include #include using namespace std;

typedef long long ll;

const int maxn = 9 * ((1 << 16) - 1);

ll _max(ll x, ll y)

int _min(int x, int y)

int read()

while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();

return s * f;

}struct node w1[110], w2[110]; int n1, n2;

int bin[30];

ll f1[1000000], f2[550000];

int main() memset(f1, -1, sizeof(f1));

f1[0] = 0; s1 = _min(s1, m / bin[11]);

for(int i = 1; i <= n1; i++)

} memset(f2, -1, sizeof(f2));

f2[0] = 0;

for(int i = 1; i <= n2; i++)

} ll ans = 0;

for(int i = 0; i <= s2; i++) f2[i] = _max(f2[i], f2[i - 1]);

for(int i = 0; i <= s1; i++) printf("%lld\n", ans);

} return 0;

}

HNOI2007 夢幻島寶珠

題目 題意簡潔明瞭,就是做乙個01揹包,但是揹包的容量 w 非常大,並且給出的物品的體積都能表示成 a times 2 b,a leq 10,b leq 30 顯然這個 a 拿來做揹包的體積非常合適,於是我們按照 b 分類,設 dp 表示只使用 a times 2 i 形式的物品,湊出 j time...

HNOI2007 夢幻島寶珠

題解 一道比較好的題目 首先比較顯然的就是我們要按照a 2 b的b的順序來列舉 那麼狀態f i j 表示當前在b,用了a 2 b 剛開始沒想到怎麼不同層之間搞 看了題解發現非常簡單 由於每一層到最後一層有用的二進位制位至少時從自己的二進位制位開始 所以我們可以捨棄那些沒用的二進位制位 maxa f ...

P3188 HNOI2007 夢幻島寶珠

傳送門 注意到 a,b 不大 考慮對每乙個 a 2 b 的 b 分別揹包 設 f i j 表示只考慮 b i 的物品時,容量為 j sum a 的最大價值 這個就是普通的 01 揹包 考慮把 f i j 之間合併起來,為了得到容量為 w 時的答案,我們要把 f 的含義稍微變化一下 變成 f i j ...