題意分析
給出 $n$ 種物品,每種物品有數量和大小,要求放入一定大小的揹包,求不能再放入任何物品的方案數。
思路分析
分析後可以發現這個問題就是在多重揹包計數問題的基礎上加上了放不進剩下的物品的條件,考慮對這個條件進行處理。
可以想到列舉剩下的物品中體積最小的物品,然後將比它小的物品先放進去,再對剩下的物品做多重揹包。每次都重新計算顯然複雜度太大,想到先將物品按照體積從大到小排序,然後一種種放入即可。
暴力多重揹包顯然是過不去的,想到用類似於單調佇列優化多重揹包的思想。但是這裡是計數問題,直接用佇列就可以了。發現求解時不需要知道佇列內具體的元素,只需要知道佇列內的元素和就可以,因此可以不進行佇列實際操作。由於計算時需要用到上一次的狀態,因此需要多開一維,可以使用滾動陣列優化。答案就是 $\sum_^ f[j]$,$sum$ 是比當前列舉到的物品小的物品大小之和。
注意,因為當前列舉的物品一定要剩下,所以再計算的時候先將當前物品個數減 $1$ ,計算結束後再用原個數更新狀態。
因為計算的情況一定有物品剩餘,因此要特判所有物品都放得下的情況。
#include#include#include#includeusing namespace std;const int n=600,m=1e5+100,p=19260817;
struct node
a[n];
int n,m,sum,ans,q;
int f[2][m];
bool cmp(node x,node y)
//按大小從大到小排序
int main()
//特判
sort(a+1,a+n+1,cmp);f[0][0]=1;//初值
for(int i=1;i<=n;i++)
}for(int j=max(m-sum-d(i)+1,0);j<=m-sum;j++)
ans=(ans+f[q][j])%p;k(i)++;//計算答案並加回來
for(int u=0;u=0)
now=(now+p-f[q^1][u+(p-k(i)-1)*d(i)])%p;
f[q][u+p*d(i)]=now=(f[q^1][u+p*d(i)]+now)%p;
}}//更新狀態
}printf("%d",ans);
return 0;
}
4 24學習計畫
1 複習模電的第一章 第二章的放大電路 2 背單詞 1 因為明天模電要期中考試啊,所以得複習一波了。講真,基礎真的超級重要。先是有了基礎,才能在基礎上進行花樣變換,就會有各種應用。由於我們在上前兩章內容的時候,授課老師生病了,我們的課是由三個任課老師輪流代上的。一邊要學習新的知識,一邊還得接受新的老...
4 24學習筆記
1.leetcode75顏色分類問題 不可以使用內建函式,思路為三指標,用red和blue分別指向當前排序好的0的後乙個位置和2的前乙個位置,white指向當前遍歷的位置,如果當前數值為0,white和red交換,如果數值為2,white和blue交換,如果數值為1,white 2.leetcode...
今日小結 4 24
1.list介面的常用子類 1 arraylist 子類 陣列list 2 linklist 子類,實現queue介面 鍊錶list 2.引用型別和原始資料型別 int 是原始型別 integer 是引用型別,是int的封裝類 為什麼要進行封裝呢?因為封裝成類就會有各種方法,方便進行型別轉換,資料處...