洛谷 U19159 采摘毒瘤
題目背景
Salamander見到路邊有如此多的毒瘤,於是見獵心喜,從家裏拿來了一個大袋子,準備將一些毒瘤帶回家。
題目描述
路邊共有nn 種不同的毒瘤,第i 種毒瘤有k_i 個,每個需要占據d_i 的空間。Salamander的袋子能裝下的最大體積為m 。
Salamander是一個很貪心的人,不過他也不要求帶盡可能多或是總體積盡可能大的毒瘤回家,他只要求袋子裏再也裝不下剩余的任何一種毒瘤。
Salamander想知道有多少種不同的裝毒瘤的方案。兩種方案不同當且僅當取的毒瘤種類不同或者至少有一種毒瘤取的數量不同。由於方案數可能太多,請輸出答案對19260817 取模後的結果。
輸入輸出格式
輸入格式:
第一行包括兩個正整數nn 、mm ,表示毒瘤的種類數和袋子的大小。
接下來的nn 行,每行兩個正整數k_i? 、d_i? ,表示一種毒瘤。
輸出格式:
一行,表示不同的方案數對19260817 取模後的結果。
輸入輸出樣例
輸入樣例#1:2 5 2 3 3 1輸出樣例#1:
2
說明
樣例解釋:
兩種方案如下:
1.取1個第一種毒瘤和2個第二種毒瘤。
2.取3個第二種毒瘤。
~ ~
對於10%的數據,1\leq n,k_i,d_i\leq 101≤n,ki?,di?≤10 ,1\leq m\leq 1001≤m≤100 ;
對於30%的數據,1\leq n,k_i,d_i\leq 501≤n,ki?,di?≤50 ,1\leq m\leq 50001≤m≤5000 ;
對於另外20%的數據,k_i=1ki?=1 ;
對於100%的數據,1\leq n,k_i,d_i\leq 5001≤n,ki?,di?≤500 ,1\leq m\leq 10^5。
多重背包的一個爛大街的優化就是單調隊列,這個沒啥好說的。。
本題可以枚舉剩的最小的體積是哪個背包,一旦最小的確定了那麽對答案有貢獻的dp數組的坐標範圍就確定了。
所以我們把物品按體積降序排序之後依次加入然後更新答案即可。。
(我當然不會告訴你這個題坑特別多)
#include<bits/stdc++.h> #define ll long long #define maxn 100005 using namespace std; const int ha=19260817; int f[2][maxn],n,m; int V,tot,sum; struct node{ int v,num; bool operator <(const node &u)const{ return v<u.v; } }a[505]; int ans=0; inline int add(int x,int y){ x+=y; if(x>=ha) x-=ha; return x; } inline int X(int x,int y){ x-=y; if(x<0) x+=ha; return x; } int main(){ scanf("%d%d",&n,&V); for(int i=1;i<=n;i++){ scanf("%d%d",&a[i].num,&a[i].v); tot+=a[i].num*a[i].v; } sort(a+1,a+n+1); if(tot<=V){ puts("1"); return 0; } f[0][0]=1; int now=0,pre; for(int i=n;i;i--){ tot-=a[i].num*a[i].v; pre=now,now^=1; int base=a[i].v,len=base*a[i].num; for(int j=0;j<base;j++){ sum=0; for(int u=j;u<=V;u+=base){ sum=add(sum,f[pre][u]); if(u-j>=len) sum=X(sum,f[pre][u-len]); f[now][u]=sum; } } int tp=V-tot; for(int j=max(0,tp-a[i].v+1);j<=tp;j++) ans=add(ans,f[now][j]); for(int j=len;j<=V;j++) f[now][j]=add(f[now][j],f[pre][j-len]); } printf("%d\n",ans); return 0; }
洛谷 U19159 采摘毒瘤