1531: [POI2005]Bank notes
时间:2019-10-30
本文章向大家介绍1531: [POI2005]Bank notes,主要包括1531: [POI2005]Bank notes使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
本人水平有限,题解不到为处,请多多谅解
本蒟蒻谢谢大家观看
题目:传送门
第一眼是完全背包,我们用完全背包的模板可以套一下,发现只会TLE三个点
直接拆分法的完全背包如下:
1 #include<bits/stdc++.h> 2 #pragma GCC optimize(3) 3 const int N=1e5+10; 4 using namespace std; 5 int n,m; 6 int b[N],c[N]; 7 int f[N]; 8 void inint(){ 9 freopen("bank.in","r",stdin); 10 freopen("bank.out","w",stdout); 11 } 12 inline int read(){ 13 int x=0,f=1;char ch=getchar(); 14 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 15 while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} 16 return x*f; 17 } 18 inline void write(int x) 19 { 20 if(x<0)x=-x,putchar('-'); 21 if(x>9)write(x/10); 22 putchar(x%10+'0'); 23 } 24 int main() 25 { 26 //inint(); 27 memset(f,0x3f,sizeof(f)); 28 f[0]=0; 29 n=read(); 30 for(int i=1;i<=n;i++){ 31 b[i]=read(); 32 } 33 for(int i=1;i<=n;i++){ 34 c[i]=read(); 35 } 36 m=read(); 37 for(int i=1;i<=n;i++){ 38 for(int j=m;j>=b[i];j--){ 39 for(int k=0;k<=c[i];k++){ 40 if(k*b[i]>j)break; 41 f[j]=min(f[j],f[j-k*b[i]]+k); 42 } 43 } 44 } 45 printf("%d\n",f[m]); 46 return 0; 47 }
但是很奇怪,用C++交题却可以AC,一转到C++11(NOI)交会TLE,可能是编译器不同吧。
正解是用二进制拆分法或单调队列优化法。
先介绍二进制拆分法:
不断把个数ci用2的几次方表示,可以把维度降到O(logci)个,效率较高。
具体证明参照《算法竞赛指南》李煜东 这本书。
例如:2^0为一组,2^1为一组,2^2为一组,2^3为一组,……
再把这些组分别进行01背包即可
code:
1 #include<bits/stdc++.h> 2 #pragma GCC optimize(3) 3 const int N=1e5+10; 4 using namespace std; 5 int n,k; 6 int b[N],c[N],f[N]; 7 void inint(){ 8 freopen("bank.in","r",stdin); 9 freopen("bank.out","w",stdout); 10 } 11 inline int read(){ 12 int x=0,f=1;char ch=getchar(); 13 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 14 while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} 15 return x*f; 16 } 17 inline void write(int x) 18 { 19 if(x<0)x=-x,putchar('-'); 20 if(x>9)write(x/10); 21 putchar(x%10+'0'); 22 } 23 void dp(int val,int num){ 24 for(int i=k;i>=val;i--){ 25 f[i]=min(f[i],f[i-val]+num);//基本01背包 26 } 27 } 28 int main() 29 { 30 //inint(); 31 n=read(); 32 memset(f,0x3f,sizeof(f)); 33 f[0]=0; 34 for(int i=1;i<=n;i++)b[i]=read(); 35 for(int i=1;i<=n;i++)c[i]=read(); 36 k=read(); 37 for(int i=1;i<=n;i++){ 38 for(int j=1;j<=c[i];j<<=1){//二进制拆分法 39 dp(b[i]*j,j); 40 c[i]-=j;//看是否还有剩余 41 } 42 if(c[i])dp(b[i]*c[i],c[i]);//把剩余的个数分为一组进行背包 43 } 44 printf("%d\n",f[k]); 45 return 0; 46 }
单调队列优化DP
使用单调队列优化可以使O(M*sigma(N)*ci)降到O(NM),与01背包中DP算法效率基本相同
code:
1 #include<bits/stdc++.h> 2 #define N 205 3 #define M 20005 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 int b[N],c[N],f[M],q[M],w[M]; 7 void inint(){ 8 freopen("bank.in","r",stdin); 9 freopen("bank.out","w",stdout); 10 } 11 int main() 12 { 13 //inint(); 14 int n,m; 15 scanf("%d",&n); 16 for (int i=1;i<=n;i++) 17 scanf("%d",&b[i]); 18 for (int i=1;i<=n;i++) 19 scanf("%d",&c[i]); 20 scanf("%d",&m); 21 memset(f,inf,sizeof(f)); 22 f[0]=0; 23 for (int i=1;i<=n;i++) 24 { 25 for (int j=0;j<b[i];j++) 26 { 27 int head=1,tail=0; 28 for (int k=j;k<=m;k+=b[i]) 29 { 30 while (head<=tail&&w[head]<k-c[i]*b[i]) head++; 31 while (head<=tail&&f[k]-(k-w[head])/b[i]<=q[tail]) tail--; 32 q[++tail]=f[k]; 33 w[tail]=k; 34 f[k]=min(f[k],q[head]+(k-w[head])/b[i]); 35 } 36 } 37 } 38 printf("%d",f[m]); 39 return 0; 40 }
原文地址:https://www.cnblogs.com/nlyzl/p/11763659.html
- Spring Cache For Redis.
- css重写checkbox样式
- 通过shell脚本同时监控多个数据库负载(r5笔记第14天)
- Java 定时器 Timer 的使用.
- 通过shell脚本来统计段大小(r5笔记第14天)
- Linux下配置MySQL主从复制(r5笔记第13天)
- Final 关键字
- ArrayList 和 LinkedList的执行效率比较
- 关于consistent gets(r5笔记第12天)
- wait/notify 实现多线程交叉备份
- 01.SVN介绍与安装
- 由sqlplus中的一个小细节所做的折腾(r5笔记第11天)
- 浅析多线程的对象锁和Class锁
- 使用strace诊断奇怪的sqlplus登录问题(r5笔记第29天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android实现View的拖拽
- 诊断日志知多少 | DiagnosticSource 在.NET上的应用
- Android Studio 4.0新特性及升级异常问题的解决方案
- Android Studio 4.0 正式发布在Ubuntu 20.04中安装的方法
- Android Studio 4.0 新功能中的Live Layout Inspector详解
- Android实现滑动刻度尺效果
- Android 仿微信发动态九宫格拖拽、删除功能
- android自定义等级评分圆形进度条
- Android Fragment实现底部通知栏
- Flutter实现局部刷新
- Android自定义条形对比统计图
- Android底部菜单栏(RadioGroup+Fragment)美化
- android自定义环形统计图动画
- 在Android环境下WebView中拦截所有请求并替换URL示例详解
- Android自定义控件横向柱状统计图