zoukankan      html  css  js  c++  java
  • Banknotes

    https://loj.ac/problem/10179

    题目描述

      有(n)中面值的硬币,每种硬币有一定的数量,求凑出面值(k)最少要多少枚硬币。

    思路

      首先比较显然的是我们可以写出一个(O(n·k·c_{max})),我们考虑暴力枚举每(i)种硬币的个数,第一维枚举钱数即可。这样理论实践复杂度肯定过不去,我们需要进行优化。考虑一下对于当前枚举的钱数(v),显然如果(k)时可取的,(k+v)也是可取的,显然会用其中代价较小的进行更新,所以我们可以第二维暴力枚举余数,对于当前余数,如果要更新(i),显然是由(i-b[i]*c[i]sim i)同余数的最小的那个,为了使得每一个数都在“同一起跑线”上,我们需要先减去两两之间差的代价。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    int read()
    {
    	int res=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    	return res*w;
    }
    
    int b[220],c[220],q[20020],pos[20020],f[20020];
    int main()
    {
    	int n=read();
    	for(int i=1;i<=n;i++)
    		b[i]=read();
    	for(int i=1;i<=n;i++)
    		c[i]=read();
    	int k=read();
    	memset(f,0x3f,sizeof(f));
    	f[0]=0;
    	for(int i=1;i<=n;i++){//cout<<i<<':'<<endl;
    		for(int j=0;j<b[i];j++)
    		{
    			int head=0,tail=0;
    			q[head]=0x3f3f3f3f;
    			for(int p=j;p<=k;p+=b[i])
    			{
    				int v=f[p]-p/b[i];
    				while(head<=tail&&pos[head]<p-c[i]*b[i])head++;
    				while(head<=tail&&q[tail]>=v)tail--;
    				q[++tail]=v;pos[tail]=p;
    				f[p]=min(f[p],q[head]+p/b[i]);
    //				cout<<p<<' '<<f[p]<<endl;
    			}
    		}
    	}
    	printf("%d
    ",f[k]);
    }
    
  • 相关阅读:
    Spring Controller参数为空串的处理方式
    netstat用法
    zookeeper的配置项
    C++ Lambda表达式用法
    java命令行运行jar里的main类
    Random的nextInt用法
    【JAVA】删除某个目录及目录下的所有子目录和文件
    Centos7设置keepAlived开机自启动
    linux设置nginx开机自启动
    window.open()方法
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11851972.html
Copyright © 2011-2022 走看看