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

dp(x)表示最大面值为x时需要的最少硬币数.

枚举x的质因数p,  dp(x) = min( dp(x/p) - (p-1) * sigma[a[i]/x] ).

----------------------------------------------------------------------------------

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

const int maxn = 59;

const int maxm = 100009;

int N, M, w[maxn], dp[maxm];

int p[maxm], minp[maxm], pn;

bool F[maxm];

template<class T>

inline void Min(T &x, T t) {

if(t < x) x = t;

}

template<class T>

inline void Max(T &x, T t) {

if(t > x) x = t;

}

void Init() {

scanf("%d", &N);

memset(dp, -1, sizeof dp);

M = dp[1] = 0;

for(int i = 0; i < N; i++) {

scanf("%d", w + i);

Max(M, w[i]);

dp[1] += w[i];

}

memset(F, 0, sizeof F);

pn = 0;

for(int i = 2; i <= M; i++) {

if(!F[i])

minp[i] = p[pn++] = i;

for(int j = 0; j < pn && i * p[j] <= M; j++) {

F[i * p[j]] = true;

minp[i * p[j]] = p[j];

if(i % p[j] == 0) break;

}

}

}

void Work() {

int ans = dp[1];

for(int i = 0; i < pn; i++) {

dp[p[i]] = 0;

for(int j = 0; j < N; j++)

dp[p[i]] += w[j] / p[i] + w[j] % p[i];

Min(ans, dp[p[i]]);

}

for(int i = 2; i <= M; i++) if(!~dp[i]) {

dp[i] = dp[1];

for(int t = i; t != 1; t /= minp[t]) {

int v = 0;

for(int j = 0; j < N; j++)

v += w[j] / i;

Min(dp[i], dp[i / minp[t]] - v * (minp[t] - 1));

}

Min(ans, dp[i]);

}

printf("%d\n", ans);

}

int main() {

Init();

Work();

return 0;

}

----------------------------------------------------------------------------------

3233: [Ahoi2013]找硬币

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 617  Solved: 275
[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

2
25 102

Sample Output

4

HINT

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

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

Source

时间: 2024-10-14 00:22:37

BZOJ 3233: [Ahoi2013]找硬币( dp )的相关文章

BZOJ 3233 Ahoi2013 找硬币 动态规划

题目大意:给定n个数,求一种混合进制使得每个数各个位之和之和最小 令fi表示表示最大硬币面值为i时零头部分(即ak mod i部分)的最小硬币数 那么有转移方程:fj=min{fi+∑nk=1?ak mod ji?}(i|j) 然后ans=min{fi+∑nk=1?aki?} 时间复杂度O(nmlogm),光荣TLE 优化:ji一定是质数,否则我可以多添加一种硬币而不伤身体(雾 那么我们只需要枚举质数倍数即可 时间复杂度O(nmloglogm),这样就可以过了 #include <cstdio>

【BZOJ 3233】 [Ahoi2013]找硬币

3233: [Ahoi2013]找硬币 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 486 Solved: 198 [Submit][Status][Discuss] Description 小蛇是金融部部长.最近她决定制造一系列新的货币.假设她要制造的货币的面值为x1,x2,x3- 那么x1必须为1,xb必须为xa的正整数倍(b>a).例如 1,5,125,250就是一组合法的硬币序列,而1,5,100,125就不是.不知从哪一天开始,可爱的蛇

BZOJ3233: [Ahoi2013]找硬币

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3233 多一点硬币是没有关系的,不用就行了. 然后有一个dp,f[i]=min(f[j]-∑a[k]/i* (i/j-1) ) 然后只要枚举i的质因子就可以了.(先线性筛出最大的质因子.. #include<cstring> #include<iostream> #include<cstdio> #include<queue> #include<cm

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

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

AOJ 169 找零钱 DP OR 母函数

一直觉得这题因为有总量限制,是不能用母函数解的,今天偶然发现原来是可以的,记录一下. 只要搞母函数的时候多开一维来表示用了多少个硬币就好了,其实就是目标状态是二维的母函数 类似于 假设我现在要处理的面值是2      (1 + x^2 * y + x^4 * y ^ 2 + x ^ 6 * y ^ 3...) 就表示用0个,1个,2个,3个..硬币的状态了. 看来母函数最重要的还是对式子本身的理解,这样才能应对各种变化. #include <cstdio> #include <cstri

BZOJ 1076 奖励关(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1076 题意:n种宝物,每个宝物有两个属性: (1)价值:(2)该宝物的集合S,只有得到了集合S中的宝物时才能得到该宝物.每次从一个黑箱子中随机拿出一个宝物k,若k的集合S中的宝物都已经得 到,则k可要(也可不要),否则k不能要.每次拿到任意宝物概率相等.求随机拿K次的最大期望得分. 思路:从后向前,设f[i][j]表示到第i次拿完宝物,状态为j的最大价值.枚举i+1次拿的宝物k,若k的

BZOJ 1560 火星藏宝图(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1560 题意: 思路:f[i]表示到达i的最大收益.这样是 O(n^2)的.我们考虑,由于转移的条件,a^2+b^2<(a+b)^2,因此对于三个点A.B.C.若A能到B,B能到C,那么A也能到C, 但是不如经过B更好.因此,我们记录到达第j列最靠下的i即可.那么转移(x,y)时,用记录的前y列即可. struct node { int x,y,w; }; node a[N]; int

BZOJ 2298 problem a(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2298 题意:一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低.”问最少有几个人没有说真话(可能有相同的分数) 思路:对于第i个人来说,区间[ai+1,n-bi]的人的分数相同.那么我们用sum[L][R]表示区间[L,R]中总人数.用f[i]表示前i个人中说真话的最大人数,那么f[j]=max(f[i-1]+sum[i][j]). map<pair<in

BZOJ 1801 中国象棋(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1801 题意:在n*m的棋盘上放若干炮使得不互相攻击.有多少种放法?可以放0个.1个....只要不互相攻击就行.. 思路:f[i][j][k]前i行j列有1个炮.k列有两个炮. int n,m; i64 f[N][N][N]; void up(i64 &x,i64 y) { x+=y; x%=mod; } i64 C(int x) { return x*(x-1)/2; } int ma