日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P3188-[HNOI2007]梦幻岛宝珠【背包】

發布時間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P3188-[HNOI2007]梦幻岛宝珠【背包】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P3188


題目大意

nnn個物品,大小為WWW的背包。

每個物品的大小可以表示為wi=ai2biw_i=a_i2^{b_i}wi?=ai?2bi?,有價值viv_ivi?

求選擇一些物品不超過背包的大小使得價值最大。


解題思路

設先計算bib_ibi?相同的物品,設fi,jf_{i,j}fi,j?表示只計算b=ib=ib=i的物品時,一個容量為j?2ij*2^{i}j?2i時的背包時的最大價值。

然后將多個背包合并,設gi,jg_{i,j}gi,j?表示只計算b≤ib\leq ibi的物品時,容量為j?2i+W&(2i?1)j*2^i+W\&(2^i-1)j?2i+W&(2i?1)時的最大價值。

然后有轉移方程gi,j=max{fi,j?k+gi?1,2k+(W>>(i?1))&1}g_{i,j}=max\{\ \ f_{i,j-k}+g_{i-1,2k+(W>>(i-1))\&1}\ \ \}gi,j?=max{??fi,j?k?+gi?1,2k+(W>>(i?1))&1???}

然后答案就是g30,0g_{30,0}g30,0?

時間復雜度O(nlog?a∑a)O(n\log a\sum a)O(nlogaa)


codecodecode

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=110; int n,W,a[N],v[N],lim[N]; int f[N][N*N],g[N][N*N]; vector<int> q[N]; int main() {while(1){ memset(f,0,sizeof(f));memset(g,0,sizeof(g));memset(lim,0,sizeof(lim));for(int i=0;i<=30;i++)q[i].clear(); scanf("%d%d",&n,&W);if(n==-1)return 0;for(int i=1;i<=n;i++){int b=0;scanf("%d%d",&a[i],&v[i]);while(a[i]>10 || !(a[i]&1))b++,a[i]/=2;q[b].push_back(i);lim[b]+=a[i];}for(int i=0;i<=30;i++)for(int j=0;j<q[i].size();j++)for(int k=lim[i];k>=a[q[i][j]];k--)f[i][k]=max(f[i][k-a[q[i][j]]]+v[q[i][j]],f[i][k]);for(int i=0;i<=lim[0];i++)g[0][i]=f[0][i];for(int i=1;i<=30;i++){lim[i]+=(lim[i-1]+1)/2;for(int j=0;j<=lim[i];j++)for(int k=0;k<=j;k++)g[i][j]=max(g[i][j],f[i][j-k]+g[i-1][min(lim[i-1],2*k+((W>>i-1)&1))]);}printf("%d\n",g[30][0]);} }

總結

以上是生活随笔為你收集整理的P3188-[HNOI2007]梦幻岛宝珠【背包】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。