[51nod1597]有限揹包計數問題
試題描述
你有乙個大小為n的揹包,你有n種物品,第i種物品的大小為i,且有i個,求裝滿這個揹包的方案數有多少
兩種方案不同當且僅當存在至少乙個數i滿足第i種物品使用的數量不同
輸入
第一行乙個正整數n
1<=n<=10^5
輸出
乙個非負整數表示答案,你需要將答案對23333333取模
輸入示例
3
輸出示例
2
資料規模及約定
見「輸入」
題解
分塊的形式真是多種多樣,這題就是乙個分塊 dp。
這裡分塊的意思是對 1~i 這 n 種物品分類討論。即對體積小於等於 sqrt(n) 的部分使用一種 dp 方法解決,對於體積大於 sqrt(n) 的部分使用另一種 dp 方法解決,最後由於「小於等於 sqrt(n) 和大於 sqrt(n) 的部分」沒有交集,相互獨立,可以使用乘法原理進行合併。
首先考慮只選用體積小於等於 sqrt(n) 的物品放入揹包,這是乙個多重揹包問題,設 f(i, j) 表示考慮前 i種物品組成體積 j 的方案數,由於這題特殊性(體積為 i 的物品有 i 個),我們可以對 j mod i 將 f(i, j) 分類(共有 i 類),然後對於 j mod i = k 的類別計算一下 f(i, j) 字首和 sum[j](共有 [n / i] 個字首和),更新 f(i+1, j) 的時候就用 sum[j] - sum[j-i*i] 就好了(記得判斷 j - i * i 會不會越界)
然後考慮體積大於 sqrt(n) 的物品,這個時候可以不考慮個數限制,因為每個物品不會選擇超過 sqrt(n) 個。考慮另一種 dp,g(i, j) 表示選擇了 i個(注意是「個」不是「種」,顯然 i ≤ sqrt(n))物品,組成體積 j 的方案數。這個 dp 中我們只關心體積最小的物品,有兩種轉移:一,放入乙個新的體積最小的物品(體積為 sqrt(n) + 1);二,所有物品體積 +1。
注意:兩種 dp 都需要開滾動陣列。
最後用乘法原理乘起來,累加,這題就解決了。
#include #include #include #include #include #include #include using namespace std;int read()
while(isdigit(c))
return x * f;
}#define maxn 100010
#define mod 23333333
#define ll long long
int n, f[maxn], g[2][maxn], gsum[maxn];
int main()
}for(j -= i; j >= mod; j -= i)
f[j] += sum;
if(f[j] >= mod) f[j] -= mod;
}}// for(int i = 0; i <= n; i++) printf("%d%c", f[i], i < n ? ' ' : '\n');
int curg = 0;
g[0][0] = 1;
for(int i = 0; i <= m; i++, curg ^= 1)
if(i && j + i <= n)
} }curg ^= 1;
int ans = 0;
for(int i = 0; i <= n; i++)
printf("%d\n", ans);
return 0;
}
51nod1597 有限揹包計數問題
你有乙個大小為n的揹包,你有n種物品,第i種物品的大小為i,且有i個,求裝滿這個揹包的方案數有多少 兩種方案不同當且僅當存在至少乙個數i滿足第i種物品使用的數量不同 n 100000,答案模23333333,時限2.333s 這道題一看是一道多重揹包,但是範圍有點大啊。可以嘗試利用一下題目的條件,對...
51Nod 1597 有限揹包計數問題
首先這是乙個多重揹包 但是它的資料非常特殊,我們可以利用其性質優化演算法 乙個顯然的優化是 當 i sqrt n 時,可以取消個數限制 設 f i j 表示選了 i 個物品,體積為 j 的方案數 一共有兩種轉移 可以由 i 1 個物品加上乙個最小的物品 sqrt n 1 可以由 i 個物品全部加一 ...
51nod 1597 有限揹包計數問題 dp
你有乙個大小為n的揹包,你有n種物品,第i種物品的大小為i,且有i個,求裝滿這個揹包的方案數有多少 兩種方案不同當且僅當存在至少乙個數i滿足第i種物品使用的數量不同 1 n 10 5,答案對23333333取模 設lim sqrt n 我們把所有物品按照大於lim和不大於lim分成兩部分。對於大於l...