zoukankan      html  css  js  c++  java
  • BZOJ 3233: [Ahoi2013]找硬币

    BZOJ 3233: [Ahoi2013]找硬币

    标签(空格分隔): OI-BZOJ OI-DP


    Time Limit: 10 Sec
    Memory Limit: 64 MB


    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####

    (f_i)表示最大面值为i所需要的最少硬币数

    [f_i=minlimits_{[j|i] &[(i/j)in{prime}]}[f[j]-sum olimits_{k=1}^n{a[k]/i}*(i/j-1)] ]

    i/j若不为质数则可以加入(其因数*j)到面额中,答案不会更劣
    a[k]/i为整除表示第k个兔子需要多少面额为i的硬币。
    一个面额为i的硬币可以替换掉i/j个面额为j的硬币,则面额为i的硬币对答案的贡献为-i/j+1
    设m=(max ai);
    这个方程直接求解复杂度是(O(m*n*log_2m))
    可以对(sum olimits_{k=1}^n{a[k]/i})预处理,复杂度(O(n*m))
    对i求j很浪费时间,虽然质数是对数级别的,但是因为m比较小,质数较多,直接枚举的话很慢。
    可以用i来更新(i*Prime_1)(i*Prime_2)(i*Prime_3)(i*Prime_4)
    总复杂度(O(n*m+m*log_2m))


    Code####

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<bitset>
    #include<vector>
    #include<time.h>
    using namespace std;
    #define PA pair<int,int>
    int read()
    {
     	int s=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
    	return s*f;
    }
    //smile please
    int n,a[55],ma;
    int di[100005],f[100005];
    int p[100005],pr[100005];
    int main()
    {
     	//freopen("a.txt","r",stdin);
    	//freopen("a.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++)
    	    a[i]=read(),f[1]+=a[i];
    	sort(&a[1],&a[n+1]);ma=a[n];
    	for(int i=ma;i;i--)
            for(int j=1;j<=n;j++)
                di[i]+=a[j]/i;
        p[1]=1;
        for(int i=2;i<=ma;i++)
            for(int j=i+i;j<=ma;j+=i)
                p[j]=1;
        for(int i=2;i<=ma;i++)
            if(!p[i])
              pr[++pr[0]]=i;
        pr[++pr[0]]=ma+1;
        int ans=f[1],k;
        for(int i=2;i<=ma;i++)f[i]=f[1];
        for(int j=1;j<=ma;j++)
           {for(int i=1,s;(s=pr[i]*j)<=ma;i++)
                f[s]=min(f[s],f[j]-di[s]*(pr[i]-1));
    		ans=min(ans,f[j]);
    	   }
    	printf("%d
    ",ans);
    	//fclose(stdin);
    	//fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    UILabel标签文字过长时的显示方式
    iOS8新特性之交互式通知
    iOS 音频学习
    UISegmentedControl小常识和图片拉伸
    iOS 锁屏判断
    UIwindow的学习
    Mac显示和隐藏系统的隐藏文件
    获取iOS系统版本和设备的电量
    React Native 学习-01
    如何用fir.im 命令行工具 打包上传
  • 原文地址:https://www.cnblogs.com/wuyuhan/p/5270263.html
Copyright © 2011-2022 走看看