zoukankan      html  css  js  c++  java
  • BZOJ3233:[AHOI2013]找硬币(DP)

    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

    2
    25 102

    Sample Output

    4

    HINT

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

    Solution

    因为选的序列是倍数的原因,所以我们可以得到一个贪心:尽可能选大的。

    也就是我们从大到小确定面额,如果当前确定的面额为$x$,那么所有兔子剩下需要付的就是$a[i]\% x$。

    设$f[i]$表示当前最小面值为$i$时的最少付钱次数。

    初始化$f[i]=sum_{j=1}^na[j]/i$。

    设$p$为$f[i]$的一个质因数

    转移$f[i/p]=min(f[i/p],f[i]+sum_{j=1}^{n} a[j]\% i/(i/p))$

    并且你需要一个线筛来快速找出一个数的所有质因数。

    为什么这么转移懒得写了,反正就是基于贪心的思想应该并不难理解QAQ

    我:为啥这个初始化不上取整啊……难不成钱不够兔子还给你抹个零……
    $sugar$:你别说还真的抹个零,因为零头在后面$DP$会付掉的……

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define N (100009)
     5 using namespace std;
     6 
     7 int n,cnt,maxn,a[N],prime[N],d[N],f[N];
     8 
     9 void Euler()
    10 {
    11     for (int i=2; i<=maxn; ++i)
    12     {
    13         if (!d[i]) {prime[++cnt]=i; d[i]=i;}
    14         for (int j=1; j<=cnt && i*prime[j]<=maxn; ++j)
    15         {
    16             d[i*prime[j]]=prime[j];
    17             if (i%prime[j]==0) break;
    18         }
    19     }
    20 }
    21 
    22 int main()
    23 {
    24     scanf("%d",&n);
    25     for (int i=1; i<=n; ++i)
    26         scanf("%d",&a[i]), maxn=max(maxn,a[i]);
    27     Euler();
    28     memset(f,0x7f,sizeof(f));
    29     for (int i=maxn; i>=1; --i)
    30     {
    31         int sum=0;
    32         for (int j=1; j<=n; ++j)
    33             sum+=a[j]/i;
    34         f[i]=min(f[i],sum);
    35         int x=i;
    36         while (x>1)
    37         {
    38             int p=d[x],sig=0;
    39             for (int j=1; j<=n; ++j)
    40                 sig+=a[j]%i/(i/p);
    41             f[i/p]=min(f[i/p],f[i]+sig);
    42             while (x%p==0) x/=p;
    43         }
    44     }
    45     printf("%d
    ",f[1]);
    46 }
  • 相关阅读:
    Python使用shape计算矩阵的行和列
    python--tile函数
    【Machine Learning in Action --3】决策树ID3算法
    python [1:3]
    python字典访问的三种方法
    python--sorted函数和operator.itemgetter函数
    python--lambda和def函数
    python--sorted函数
    【转载】梦断计院--一个计算机学院学生大学学习生活的回顾与反省
    jquery源码学习-初始(1)
  • 原文地址:https://www.cnblogs.com/refun/p/10221870.html
Copyright © 2011-2022 走看看