BZOJ1531: [POI2005]Bank notes
1531: [POI2005]Bank notes
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 229 Solved: 119
[Submit][Status]
Description
Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有n种面值的硬币,面值分别为b1, b2,..., bn. 但是每种硬币有数量限制,现在我们想要凑出面值k求最少要用多少个硬币.
Input
第一行一个数 n, 1 <= n <= 200. 接下来一行 n 个整数b1, b2,..., bn, 1 <= b1 < b2 < ... < b n <= 20 000, 第三行 n 个整数c1, c2,..., cn, 1 <= ci <= 20 000, 表示每种硬币的个数.最后一行一个数k – 表示要凑的面值数量, 1 <= k <= 20 000.
Output
第一行一个数表示最少需要付的硬币数
Sample Input
Sample Output
HINT
Source
题解:
应该算是一个比较裸的多重背包问题。
顺便复习了下 单调队列优化多重背包 。
好像很优越:对于第 i 种物品来说,已知体积 v,价值 w,数量 k,那么可以按照当
我们可以把每一份分开处理,假设余数为 d。
现在看到分组以后,编号 j 可以从 j-k 到 j-1 中的任意一个编号转移而
来(因为相邻的体积正好相差 v),这看上去已经和区间最大值有点相似了。
但是注意到由于体积不一样,显然体积大的价值也会大于等于体积小的,
直接比较是没有意义的,所以还需要把价值修正到同一体积的基础上。比
如都退化到 d,也就是说用 F[j*v+d]- j*w 来代替原来的价值进入队列
代码:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set> 10 #include<queue> 11 #include<string> 12 #define inf 1000000000 13 #define maxn 50000 14 #define maxm 500+100 15 #define eps 1e-10 16 #define ll long long 17 #define pa pair<int,int> 18 #define for0(i,n) for(int i=0;i<=(n);i++) 19 #define for1(i,n) for(int i=1;i<=(n);i++) 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 22 #define mod 1000000007 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 28 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 int n,m,a[maxn],b[maxn],f[maxn]; 32 struct rec{int x,y;}q[maxn]; 33 int main() 34 { 35 freopen("input.txt","r",stdin); 36 freopen("output.txt","w",stdout); 37 n=read(); 38 for1(i,n)a[i]=read(); 39 for1(i,n)b[i]=read(); 40 m=read(); 41 memset(f,60,sizeof(f)); 42 f[0]=0; 43 for1(i,n) 44 { 45 for0(j,a[i]-1) 46 { 47 int l=1,r=0; 48 for0(k,(m-j)/a[i]) 49 { 50 int t=k*a[i]+j; 51 while(l<=r&&q[r].y>f[t]-k)r--; 52 q[++r].x=k;q[r].y=f[t]-k; 53 while(l<=r&&q[l].x<k-b[i])l++; 54 if(l<=r)f[t]=min(f[t],q[l].y+k); 55 } 56 } 57 } 58 printf("%d\n",f[m]); 59 return 0; 60 }