[bzoj3233] [Ahoi2013]找硬币
一开始没什么思路...后来想到确定最大硬币面值就知道其他面值能取多少了。。而且结果是可以由较小的面值转移过来的。
f[i]表示最大面值为i时的最小硬币数。a[i]表示第i个物品的价钱。
f[i]=min{ f[ i / j ]- sum{ a[ k ] / i * ( j-1 ) } },(j是i的因数)
对于物品k,我们能用a[k]/i 枚面值为i的硬币。显然肯定都用上啦。
而且现在我们用面值i 的硬币拼出来的价钱,本来肯定都是用面值为( i / j )的硬币拼的。(因为j是i的因数,所以能用( i / j )的拼;又因为( i / j )是之前的最大面额,所以肯定会用)
所以我们用a[k]/i枚面值为i 的硬币能够减少a[k]/i*(j-1)枚面值为( i / j )的硬币的使用。(感谢JSZX11556老司机指正。。已修改)
然后又因为显然,在符合条件的情况下面值种类越多越好(至少不会更差)。。所以我们使j为质数就好了。(若j是合数的话,我们可以先增加其他面额,然后从另一种面值转移到i,所以j不取合数对答案没影响)
线性筛质数的时候可以顺便求出每个数的最小质因数,然后就可以做到只枚举i的质因数了。
时间复杂度O(n*sum*loglogsum),(sum为所有兔纸价钱的总和)(复杂度分析参考埃氏筛法= =)
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #define ll long long
- using namespace std;
- int mn[],pri[],f[],cnt,mx;
- int a[];
- bool cant[];
- int i,j,k,n,m,ans;
- inline void prerun(int mx){
- for(i=;i<=mx;i++){
- if(!cant[i])pri[++cnt]=i,mn[i]=i;
- for(k=i<<,j=;j<=cnt&&k<=mx;k=i*pri[++j]){
- cant[k]=,mn[k]=pri[j];
- if(!(i%pri[j]))break;
- }
- }
- }
- int ra;char rx;
- inline int read(){
- rx=getchar(),ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- inline int min(int a,int b){return a<b?a:b;}
- int main(){
- // memset(f,60,(n+1)<<2);f[1]=0;
- n=read();
- for(i=;i<=n;i++)mx=max(mx,a[i]=read()),f[]+=a[i];
- prerun(mx);
- register int i,j,k,tmp,sm;
- for(i=;i<=mx;i++)f[i]=f[];ans=f[];
- for(i=;i<=mx;ans=min(ans,f[i]),i++)
- for(tmp=i;tmp>;f[i]=min(f[i],sm)){
- // printf(" %d %d\n",f[i],f[i/mn[tmp]]);
- for(sm=f[j=i/mn[tmp]],k=;k<=n;k++)sm-=a[k]/i*(mn[tmp]-);
- while(mn[tmp]==mn[tmp/mn[tmp]])tmp/=mn[tmp];tmp/=mn[tmp];
- }
- printf("%d\n",ans);
- return ;
- }
[bzoj3233] [Ahoi2013]找硬币的更多相关文章
- [Bzoj3233][Ahoi2013]找硬币[基础DP]
3233: [Ahoi2013]找硬币 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 924 Solved: 482[Submit][Status][ ...
- BZOJ3233:[AHOI2013]找硬币(DP)
Description 小蛇是金融部部长.最近她决定制造一系列新的货币.假设她要制造的货币的面值为x1,x2,x3… 那么x1必须为1,xb必须为xa的正整数倍(b>a).例如 1,5,125, ...
- [AHOI2013]找硬币(搜索)
[Ahoi2013]找硬币 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 348 Solved: 114[Submit][Status] Descri ...
- BZOJ 3233: [Ahoi2013]找硬币( dp )
dp(x)表示最大面值为x时需要的最少硬币数. 枚举x的质因数p, dp(x) = min( dp(x/p) - (p-1) * sigma[a[i]/x] ). ----------------- ...
- BZOJ 3233: [Ahoi2013]找硬币
BZOJ 3233: [Ahoi2013]找硬币 标签(空格分隔): OI-BZOJ OI-DP Time Limit: 10 Sec Memory Limit: 64 MB Description ...
- 【bzoj 3233】[Ahoi2013]找硬币 ——搜索
Description 小蛇是金融部部长.最近她决定制造一系列新的货币.假设她要制造的货币的面值为x1,x2,x3… 那么x1必须为1,xb必须为xa的正整数倍(b>a).例如 1,5,125, ...
- 【BZOJ 3233】 [Ahoi2013]找硬币
[题目 描述] 小蛇是金融部部长. 最近她决定制造一系列新的货币. 假设她要制造的货币 的面值为 x1, x2, x3… 那么 x1 必须为 1, xb 必须为 xa 的正整数倍(b>a). 例 ...
- 【bzoj3233】【ahoi2013】找硬币
题意: 求确定n种货币面额x1..xn满足 x1=1 且xi为xj的整数倍(i>j) 给定n个物品价格ai 求使用上面货币最少需要硬币数(不能找零) 题解: 动态规划 听说网上的题解都是搜索的做 ...
- BZOJ3233【AHOI2013】找硬币
题面 题解 最优肯定是尽可能用大面值硬币 设$f[i]$表示最小面值为$i$时的最小答案 则:(令$p$是$i$的最小质因子) $$ f[\frac ip]=min(f[\frac ip], f[i] ...
随机推荐
- Java I/O---字符与字节转换流---FileReader&FileWriter:
public class SubTransStreamDemo { /** * @param args * @throws IOException */ public static void ma ...
- NET Framework 版本和依赖关系
原文:https://docs.microsoft.com/zh-cn/dotnet/framework/migration-guide/versions-and-dependencies 每个版本的 ...
- HTML知识点记录
1.input的type设置为file时,设置multiple属性可以同时选择多个文件.
- 在Windows上运行Linux
在Windows上运行Linux 之前了解过一些适用于linux的Windows子系统,最近又听人提起,于是在自己的Windows 10专业版上安装了一个Ubuntu.运行起来还真方便,以后在wind ...
- Disruptor并发框架(一)简介&上手demo
框架简介 Martin Fowler在自己网站上写了一篇LMAX架构的文章,在文章中他介绍了LMAX是一种新型零售金融交易平台,它能够以很低的延迟产生大量交易.这个系统是建立在JVM平台上,其核心是一 ...
- C# Log4net记录日志
前言 1.需求 需求很简单,就是在C#开发中高速写日志.比如在高并发,高流量的地方需要写日志.我们知道程序在操作磁盘时是比较耗时的,所以我们把日志写到磁盘上会有一定的时间耗在上面,这些并不是我们想看到 ...
- 几种加密算法的java实现包括MD5、RSA、SHA256
SHA加密: package com; import java.security.MessageDigest;import java.security.NoSuchAlgorithmException ...
- 在Ubuntu下安装OpenJDK的方法
最近在看<深入理解Java虚拟机>就想试一下在ubuntu下安装一个自己的虚拟机,说实话还是废了些功夫的. 首先我的ubuntu版本是Ubuntu 14.04.5, 于是我就去OpenJD ...
- Python函数返回不定数量的值
Python的函数是可以return多个值的,但其本质上还是返回单个值,只是利用了tuple的自动打包,将多个值打包成单个tuple返回. 使用代码验证: def func_a(): return 1 ...
- Linux入门篇(二)——文件
这一系列的Linux入门都是本人在<鸟哥的Linux私房菜>的基础上总结的基本内容,主要是记录下自己的学习过程,也方便大家简要的了解 Linux Distribution是Ubuntu而不 ...