内容概述
本篇有两题
第二题为第一题的进阶,个人感觉题很不错
1.题目传送门
大致思路
选取100个数组内的数 k ($1≦k≦10$) 可以明确的是n足够大(可选够多)时肯定可以选出来,接下来讨论怎么解决 n 比较小的时候
我们可以用一个桶记录这些数出现的次数 cnt
十的倍数我们可以转化为 末位数字为 0 的数字 ,那么怎么转化为背包问题?
选100个数(容量) ,这些数字的末位数字就为价值
记dp[s][r],s为当前选了多少数,r表示能取到的末位数字.
遍历每一个数字(1-10) 对应末位数字为 0-9 ,做一个背包问题
$$dp[s+t][newr]=dp[s][oldr] $$
newr为oldr加上选择的t个数字得到的末位数字,注意要倒序遍历,否则会出现重复利用的操作
Code
1 | #include <bits/stdc++.h> |
2.题目传送门
大概算是上一题的进阶题
大致思路
首先观察数据范围 $(1≦n≦100)$ 和 $(1≦a_i≦200)$ 可以想到枚举出部分范围的有趣数,可以写一个程序来枚举1-20000的所有有趣数
为什么是 1-20000 ? 想一想这个数据范围能组成的最大总和是多少? $20000$ !
为什么说这题是上一题的进阶题,因为很明显, 1 是一个有趣数,无论怎么样,我们都可以将数组中的n-1个元素变为1,剩下一个元素承担剩下的总和.(也是因为这一点,打上了思维tag)
那什么情况下答案可以是 n ? 就是这 n 个数的总和与由 n 个有趣数构成的总和相等的时候
此时可以转化为上一题的背包问题
记dp[i][j],i为选了多少数,j为当前总和,有下面状态转移方程
$$dp[i][j]=dp[i-1][j-x] $$
其中x为有趣数,因为这里任一有趣数的数量是"无限"的,所以不用考虑重复利用问题.
补充:考虑预处理
Code
Assistance
1 | int getDigit(int x) { |
Solution
1 | #include <bits/stdc++.h> |
说些什么吧!