• 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 }
  • 相关阅读:
    [转]Angular2-组件间数据传递的两种方式
    [转]Angular4---部署---将Angular项目部署到IIS上
    [转]Angular开发(十八)-路由的基本认识
    [转]【Angular4】基础(一):脚手架 Angular CLI
    [转]【Angular4】基础(二):创建组件 Component
    [转]Angular项目目录结构详解
    [转]Ionic国际化解决方案
    [转]Angular CLI 安装和使用
    [转]nodejs之cordova 跨平台开发
    [转]Windows下配置Node.js和Cordova
  • 原文地址:https://www.cnblogs.com/refun/p/10221870.html
Copyright © 2020-2023  润新知