3233: [Ahoi2013]找硬币


Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 924  Solved: 482
[Submit][Status][Discuss]

Description


小蛇是金融部部长。最近她决定制造一系列新的货币。假设她要制造的货币的面值为x1,x2,x3… 那么x1必须为1,xb必须为xa的正整数倍(b>a)。例如 1,5,125,250就是一组合法的硬币序列,而1,5,100,125就不是。不知从哪一天开始,可爱的蛇爱上了一种萌物——兔纸!从此,小蛇便走上了遇上兔纸娃娃就买的不归路。某天,小蛇看到了N只可爱的兔纸,假设这N 只兔纸的价钱分别是a1,a2…aN。现在小蛇想知道,在哪一组合法的硬币序列下,买这N只兔纸所需要的硬币数最少。买兔纸时不能找零。
 
 
 

Input


第一行,一个整数N,表示兔纸的个数
第二行,N个用空格隔开的整数,分别为N只兔纸的价钱
 
 
 

Output


一行,一个整数,表示最少付的钱币数。

 
 
 

Sample Input


Sample Output


HINT


样例解释:共有两只兔纸,价钱分别为25和102。现在小蛇构造1,25,100这样一组硬币序列,那么付第一只兔纸只需要一个面值为25的硬币,第二只兔纸需要一个面值为100的硬币和两个面值为1的硬币,总共两只兔纸需要付4个硬币。这也是所有方案中最少所需要付的硬币数。

1<=N<=50, 1<=ai<=100,000

分析:


本来凑面值的题就是十分亲民的题,再加上数据又十分亲民,所以就是一道十分亲民的题……。

定义状态f[i]表示最大硬币为i面值时的最少硬币。转移方程f[i] = min(f[i],f[j] - sum((a[k] / i)* (i / j - 1)));(j为i的因子,k为每只兔子价格)

为什么这么转移,因为比如说我们有三枚三元硬币,我们可以转换成一枚九元硬币。

很简单,比如说我们有一只兔子价格为28,用1元硬币去凑会用28枚(即f[1] = 28),用1、3去凑会有  f[3] = f[1] - 28 / 3 * (3 / 1 - 1) = 10枚硬币,用1,3,9去凑会有f[9] = f[3] -  28 / 9 * (9 / 3 - 1) = 4枚硬币。

其实转移是很简单的,但是发现i的范围是100,000 ,j是i的因子需要去转化,k是每只兔子,复杂度很高的。我们可以考虑省掉j。即我们用递推。

可以由f[j]倒推f[i]。

发现100000 内每个数 不停加本身,推到100000,再乘上50只兔子的复杂度才几千万,随便卡过。

我一开始是这么做的,于是4.6S过了(数据太亲民了)。

其实后面我想了一下还可以优化,因为比如说f[27]由f[9]推过去肯定比由f[3]推过去优,所以对于每个数我们只用去推它的质数倍数就好了。

设M =100,000,N = 50;

K 为 M内所有数乘以质数倍推到100000的复杂度(好像这个数才十万左右....)

筛素数(M loglog M),递推(N *  K)所以复杂度是(M log log M + N * K)。然后就从4.6S降到了1.6S。话说数据是真亲民啊……

附上AC代码:


  1. # include <iostream>
  2. # include <cstdio>
  3. # include <cstring>
  4. # include <algorithm>
  5. using namespace std;
  6. const int N = ;
  7. const int M = 1e5 + ;
  8. int a[N],n;
  9. int f[M],ans,sum,maxn,cnt,p[M];
  10. bool vis[M];
  11. void shai(){
  12. for(int i = ;i < M;i++){
  13. if(!vis[i])p[++cnt] = i;
  14. for(int j = ;j <= cnt;j++){
  15. if(p[j] * i >= M)break;
  16. vis[p[j] * i] = true;
  17. if(i % p[j] == )break;
  18. }
  19. }
  20. }
  21. void Init(){
  22. memset(f,0x3f3f3f3f,sizeof f);
  23. }
  24. int dp(int i,int j){
  25. int ans = f[j];
  26. for(int k = ;k <= n;k++){
  27. ans -= (a[k] / i) * (i / j - );
  28. }
  29. return ans;
  30. }
  31. int main(){
  32. Init();
  33.  
  34. scanf("%d",&n);
  35. for(int i = ;i <= n;i++){
  36. scanf("%d",&a[i]);sum += a[i];
  37. maxn = max(maxn,a[i]);
  38. }
  39. f[] = sum;ans = f[];
  40. for(int i = ;i <= maxn;i++){
  41. f[i] = min(f[i],dp(i,));
  42. ans = min(ans,f[i]);
  43. }
  44. shai();
  45. for(int i = ;i <= maxn;i++){
  46. for(int j = ;j <= cnt;j++){
  47. if(p[j] * i > maxn)break;
  48. f[p[j] * i] = min(f[p[j] * i],dp(p[j] * i,i));
  49. ans = min(ans,f[p[j] * i]);
  50. }
  51. }
  52. printf("%d\n",ans);
  53. }

[Bzoj3233][Ahoi2013]找硬币[基础DP]的更多相关文章

  1. BZOJ3233:[AHOI2013]找硬币(DP)

    Description 小蛇是金融部部长.最近她决定制造一系列新的货币.假设她要制造的货币的面值为x1,x2,x3… 那么x1必须为1,xb必须为xa的正整数倍(b>a).例如 1,5,125, ...

  2. [bzoj3233] [Ahoi2013]找硬币

    一开始没什么思路...后来想到确定最大硬币面值就知道其他面值能取多少了..而且结果是可以由较小的面值转移过来的. f[i]表示最大面值为i时的最小硬币数.a[i]表示第i个物品的价钱. f[i]=mi ...

  3. BZOJ 3233: [Ahoi2013]找硬币( dp )

    dp(x)表示最大面值为x时需要的最少硬币数. 枚举x的质因数p,  dp(x) = min( dp(x/p) - (p-1) * sigma[a[i]/x] ). ----------------- ...

  4. [AHOI2013]找硬币(搜索)

    [Ahoi2013]找硬币 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 348  Solved: 114[Submit][Status] Descri ...

  5. BZOJ 3233: [Ahoi2013]找硬币

    BZOJ 3233: [Ahoi2013]找硬币 标签(空格分隔): OI-BZOJ OI-DP Time Limit: 10 Sec Memory Limit: 64 MB Description ...

  6. 【bzoj 3233】[Ahoi2013]找硬币 ——搜索

    Description 小蛇是金融部部长.最近她决定制造一系列新的货币.假设她要制造的货币的面值为x1,x2,x3… 那么x1必须为1,xb必须为xa的正整数倍(b>a).例如 1,5,125, ...

  7. 【BZOJ 3233】 [Ahoi2013]找硬币

    [题目 描述] 小蛇是金融部部长. 最近她决定制造一系列新的货币. 假设她要制造的货币 的面值为 x1, x2, x3… 那么 x1 必须为 1, xb 必须为 xa 的正整数倍(b>a). 例 ...

  8. 「kuangbin带你飞」专题十二 基础DP

    layout: post title: 「kuangbin带你飞」专题十二 基础DP author: "luowentaoaa" catalog: true tags: mathj ...

  9. 找规律/数位DP HDOJ 4722 Good Numbers

    题目传送门 /* 找规律/数位DP:我做的时候差一点做出来了,只是不知道最后的 is_one () http://www.cnblogs.com/crazyapple/p/3315436.html 数 ...

随机推荐

  1. pocket API学习笔记

    最近安装了pocket离线阅读软件. 为了收藏需要的URL,每次都要打开浏览器.然后按google工具条上的pocket+. 网页多的时候,这个过程就非常缓慢. 根据pocket网站的API介绍,我可 ...

  2. Android系统级技巧合集

    Android系统级技巧合集(随时更新) #转载请注明来源# 1.高通骁龙系列查看CPU体质等级 CPU体质,即为CPU在工作频率下的电压.同一批次的CPU体质各有不同,体质越高,代表该颗CPU可在更 ...

  3. uva820 Internet Bandwidth

    就是模板... #include<cstdio> #include<cstring> #include<vector> #include<queue> ...

  4. LinkdList和ArrayList异同、实现自定义栈

    //.LinkdList和ArrayList异同 //ArrayList以连续的空间进行存储数据 //LinkedList以链表的结构存储数据 //栈 先进后出 最上面是栈顶元素 arrayLiat自 ...

  5. JAVA自定义栈

    public class Stack{ int[] data; int maxSize; int top; public Stack(int maxSize) { this.maxSize=maxSi ...

  6. 整理几个牛人博客以及OJ

    Blogs 陈立杰(wjmzbmr):http://wjmzbmr.com/ 飘过的小牛:http://blog.csdn.net/niushuai666 王垠:http://www.yinwang. ...

  7. python-opencv遍历图片像素,并对像素进行操作

    看代码: def access_pixels(frame): print(frame.shape) #shape内包含三个元素:按顺序为高.宽.通道数 height = frame.shape[0] ...

  8. Python自动化测试框架——断言

    在自动化测试执行的过程中,我们往往希望可以自定生成报告,那如何再测试中进行验证呢?我们使用断言 import unittest class TestCount(unittest.TestCase): ...

  9. 【JDBC-MVC模式】开发实例

    JDBC - 开发实例-MVC模式  1. 在web.xml中配置连接数据库的信息 web.xml: <context-param> <param-name>server< ...

  10. python基础知识11-文件操作

    文件 装饰器,装饰函数或者类的方法. 1.文件的基本操作 打开文件: 注意绝对路径与相对路径. path = 'text.txt' path = r'/home/pyvip/py_case/text. ...