ZROI117 【17 普及 23】知足
尽管这些题目都是五月天的经典歌曲,但和五月天毫无关系(好歹说一句:小明正在听五月天的歌《知足》,突然心情很差,想出了一道机智的题,希望机(yu)智(chun)的你去切(bu cun zai de)了他。
你现在正在设计一套新的货币系统。这套货币系统有以下要求:
- 一共有 K种面值的纸币(没有硬币等其他货币)。
- 最小的纸币面值为 1 元。
- 每种纸币的面值为前一种纸币面值的 2 或 3 或 4 或 5 倍。
输入格式
输入一行两个正整数 n 和 K,以一个空格隔开。输出格式
输出一个正整数,表示凑出 n 元至少需要的纸币数量。样例输入
1025 6
样例输出
2
样例说明
纸币面值:1, 4, 16, 64, 256, 1024。数据规模和约定
子任务1(20分):n≤10^18,K≤10 子任务2(80分):n≤10^18,K≤100题解
感觉智商越来越低了,,动态开点线段树被做成单调队列,nuo,普及组的题都只能敲暴力,orz orz 20分做法,爆搜。 满分做法:dp[n,k]表示,还可以新有K种货币,将这k+1种货币构成n元钱的最小纸币张数,并且第K+1的面额为1。 有个很显然的贪心我们也在上述20分爆搜写的时候发现,在一组货币后,我们一定是优先选金额大的再选金额小的。而这里,我们枚举一下一张货币的面额(从2-->5)d,那么一定是后面的货币分配了n-n%d元,这样才更优。由于那n%d太小,只有面额1能选便分配。 这样之后看似我们与之前定的面额矛盾,因为现在变成了K+1面额为d了。但实际上我们如果将(n-n%d)和面额d同时除上一个d,那么我们就又转化为之前的dp状态了。 那么就有 dp[n,k] = for ( d 2-->5) min(dp[n,k],dp[(n-n%d)/d,k-1]+n%d) 这里面有很多冗余状态,且显然数组存不下。我们开个hash表或者map都是可以的。 code:#include<iostream> #include<map> #include<cstdio> #include<algorithm> using namespace std; map<long long,long long>dp[105]; long long n,k; long long dfs(long long n,long long k) { if(dp[k][n]) return dp[k][n]; if(k==1) return n; if(!n) return 0; long long bbest = 1e18; for(int i=2;i<=5;i++) { bbest = min(bbest,dfs(n/i,k-1)+n%i); } return dp[k][n] = bbest; } int main() { scanf("%lld%lld",&n,&k); printf("%lld",dfs(n,k)); }