Bzoj3233 [Ahoi2013]找硬币

 

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 804  Solved: 408

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

Source

 

动态规划 刷表DP 脑洞题

题目令人十分迷茫,看了题解以后忍不住想大呼“还有这种操作”

会这么想的绝对只有我一个人

 

设$ f[i] $表示把“用面值为i的硬币付不掉的那部分”干掉 (也就是清除“边角料”)的最小花费。

设$ g[i] $表示最多可以使用的面值为i的硬币的数量(因为硬币面值都是倍数关系,所以能用大的肯定先用大的)。

显然这两个是互补的。

那么显然 ans = min{ f[i] + g[i] }

对于每个i,枚举i的质数倍,有转移:

  $f[ prime[j] * i ] = min ( f[ prime[j] * i , f[i] + calc(i , k) )$

这个calc(i,k)是将用k不能解决的部分用i解决所需的硬币i的个数。具体统计方式见代码。

注意除法是整除。

那么问题来了,用i去支付的时候,i不能解决的部分是不是因为整除而漏算了呢?并没有,这部分被统计在f[i]里了

会在这个地方转不过弯的绝对只有我一个人

预处理一下质数,就可以愉快地解决了

因为看着和线性筛有些像,于是试着加了57行那个break,然而是错的2333

 

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 using namespace std;
 7 const int N=100010;
 8 const int mxn=60;
 9 int read(){
10     int x=0,f=1;char ch=getchar();
11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
13     return x*f;
14 }
15 int n,a[mxn];
16 int mx;
17 int pri[N],cnt=0;
18 bool vis[N];
19 int f[N];
20 void init(){
21     for(int i=2;i<=mx;i++){
22         if(!vis[i]){
23             pri[++cnt]=i;
24         }
25         for(int j=1;j<=cnt && pri[j]*i<=mx;i++){
26             vis[pri[j]*i]=1;
27             if(i%pri[j]==0)break;
28         }
29     }
30     return;
31 }
32 int calc(int x,int mod){
33     int res=0;
34     if(!mod){
35         for(int i=1;i<=n;i++)
36             res+=a[i]/x;
37         return res;
38     }
39     for(int i=1;i<=n;i++)
40         res+=a[i]%mod/x;
41     return res;
42 }
43 int main(){
44     int i,j,k;
45     n=read();
46     for(i=1;i<=n;i++)a[i]=read(),mx=max(mx,a[i]);
47     init();
48     sort(a+1,a+n+1);
49     memset(f,0x3f,sizeof f);
50     f[1]=0;
51     int ans=0x3f3f3f3f;
52     for(i=1;i<=mx;i++){
53         ans=min(ans,f[i]+calc(i,0));
54         for(j=1;j<=cnt && ((k=pri[j]*i)<=mx);j++){
55             f[k]=min(f[k],f[i]+calc(i,k));
56 //            printf("i:%d k:%d fi:%d fk:%d\n",i,k,f[i],f[k]);
57 //            if(i%pri[j]==0)break; //WA
58         }
59     }
60     printf("%d\n",ans);
61     return 0;
62 }

 

posted @ 2017-06-22 21:57  SilverNebula  阅读(324)  评论(0编辑  收藏  举报
AmazingCounters.com