[BZOJ]4265 货币系统

题意

一个货币系统要求一共有 m 种货币,并且将它们按照币值从小到大排好序以后,前一个货币币值乘上 x 等于后一个货币币值,\(x ∈ {2, 3, 4, 5}\),且最小的币值一定为 1。

请设计一个货币系统,使得它表示总币值为 n 的钱所需的货币总张数最少。

\(n ≤ 10^18\)
\(m ≤ 100\)
Source : BZOJ 4265

题解

下一个货币照顾不到前一个货币能照顾的情况。

假如说x只有一个,就是x进制,其实x有四个跟一个没有区别的。

最终可以把n写成这样的一个式子

\[n=1*(k_1*(a_1+(k_2*(a_2+...)))) \]

最终的答案数应该是\(a_1+a_2+\dots+a_n\)

只要按照进制的算法,每次除\(k_i\)取余求一个最小值就行了。

注意这里n比较大,但是实际上用到的状态数其实很小,可以用map代替数组。

时间复杂度\(O(mlog^3n)\)

#include <bits/stdc++.h>
#define int long long
#define Mid ((l + r) >> 1)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
int read(){
	char c; int num, f = 1;
	while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
	while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
	return f * num;
}
int n, m;
map<int,int> f[105];
int dfs(int x, int y) {
	if(f[x].count(y)) return f[x][y];
	if(y == 0) return 0;
	if(x == 1) return y;
	int minn = 1e18;
	for(int i = 2; i <= 5; i++) 
		minn = min(minn, dfs(x - 1, y / i) + y % i);
	f[x][y] = minn;
	return f[x][y];
}
signed main()
{
	n = read(); m = read();
	printf("%lld\n", dfs(m, n));
	return 0;
}
posted @ 2021-02-07 15:56  _onglu  阅读(109)  评论(0编辑  收藏  举报