• Codeforces Round #834 (Div. 3)(D-G)


    D. Make It Round

    可知题意是让求一定操作数内要能得到的数末尾的0最多是几

    根据数的唯一分解定理,末尾为0的个数只取决于2和5的数量,因为最多18个0,也就是最多18对2和5,然后得到对应的操作次数即可

    AC代码:

    1. /*##########################################################
    2. # File Name: 2.cpp
    3. # Author: HideInTheSea
    4. # Created Time: 2022年11月20日 星期日 19时24分47秒
    5. ##########################################################*/
    6. #include
    7. using namespace std;
    8. using LL = long long;
    9. void Solve() {
    10. LL n, m;
    11. cin >> n >> m;
    12. for (int i = 18; i >= 0; i--) {
    13. LL x = n;
    14. int cnt2 = i, cnt5 = i;
    15. while (x % 2 == 0) {
    16. x /= 2;
    17. cnt2--;
    18. }
    19. while (x % 5 == 0) {
    20. x /= 5;
    21. cnt5--;
    22. }
    23. LL y = 1;
    24. for (int j = 0; j < cnt2; j++) {
    25. y *= 2;
    26. }
    27. for (int j = 0; j < cnt5; j++) {
    28. y *= 5;
    29. }
    30. if (y <= m) {
    31. LL k = m / y * y;
    32. cout << n * k << '\n';
    33. return;
    34. }
    35. }
    36. }
    37. int main() {
    38. ios::sync_with_stdio(false);
    39. cin.tie(nullptr);
    40. int T;
    41. cin >> T;
    42. while (T--) {
    43. Solve();
    44. }
    45. return 0;
    46. }

    E. The Humanoid

    挺不错的DP题

    主角有两瓶绿色药水和一瓶蓝色药水

    主角每秒可以执行三种操作:

    1.主角吸收随从能量的一半

    2.主角喝绿色药水能量乘2

    3.主角喝蓝色药水能量乘3

    问最多吸收多少随从

    首先贪心的去想随从能量越小,越要放在前面,这样最容易吸收他的能量而不浪费药水,然后再考虑DP

    状态边界为dp[0][i][j],分别为喝了i瓶绿色药水和喝了j瓶蓝色药水

    dp[i][j][k]表示到达第i秒用了j瓶绿色药水和k瓶蓝色药水时最大的能量值和吸收随从的次数,转移就是分别模拟三种操作

    AC代码:

    1. /*##########################################################
    2. # File Name: 1.cpp
    3. # Author: HideInTheSea
    4. # Created Time: 2022年11月22日 星期二 18时06分06秒
    5. ##########################################################*/
    6. #include
    7. using namespace std;
    8. using LL = long long;
    9. void Solve() {
    10. int n;
    11. LL h;
    12. cin >> n >> h;
    13. vector<int> a(n + 1);
    14. for (int i = 1; i <= n; i++) {
    15. cin >> a[i];
    16. }
    17. sort(a.begin() + 1, a.end());
    18. vectorint>>>> dp(n + 1, vectorint>>> (3, vectorint>> (2)));
    19. for (int i = 0; i < 3; i++) {
    20. for (int j = 0; j < 2; j++) {
    21. dp[0][i][j].first = h * (i == 0 ? 1 : 2) * (j == 0 ? 1 : 3) * (i == 2 ? 2 : 1);
    22. dp[0][i][j].second = 0;
    23. }
    24. }
    25. for (int i = 1; i <= n; i++) {
    26. for (int j = 0; j < 3; j++) {
    27. for (int k = 0; k < 2; k++) {
    28. dp[i][j][k] = make_pair(dp[i - 1][j][k].first + (dp[i - 1][j][k].first > a[i]) * a[i] / 2, dp[i - 1][j][k].second + (dp[i - 1][j][k].first > a[i]));
    29. }
    30. }
    31. dp[i][0][1] = max(dp[i][0][1], pairint> {dp[i][0][0].first * 3, dp[i][0][0].second});
    32. dp[i][1][1] = max({dp[i][1][1], pairint> {dp[i][1][0].first * 3, dp[i][1][0].second}, pairint> {dp[i][0][1].first * 2, dp[i][0][1].second}});
    33. dp[i][1][0] = max(dp[i][1][0], pairint> {dp[i][0][0].first * 2, dp[i][0][0].second});
    34. dp[i][2][1] = max({dp[i][2][1], pairint> {dp[i][2][0].first * 3, dp[i][2][0].second}, pairint> {dp[i][1][1].first * 2, dp[i][1][1].second}});
    35. dp[i][2][0] = max(dp[i][2][0], pairint> {dp[i][1][0].first * 2, dp[i][1][0].second});
    36. }
    37. cout << dp[n][2][1].second << '\n';
    38. }
    39. int main() {
    40. ios::sync_with_stdio(false);
    41. cin.tie(nullptr);
    42. int T;
    43. cin >> T;
    44. while (T--) {
    45. Solve();
    46. }
    47. return 0;
    48. }

    F. All Possible Digits

    首先要看清题干,给出一段在p进制下的数,虽然每次操作可以选择任意一位数,但最后写在黑板上的是x+1,也就是说每次操作只能最低位+1

    那么首先想到的是进行p-1次操作一定能完成任务,但操作数太多了,题目要最小化

    其次想到最低位是否要进位?

    如果不进位,前提是除最低位以外的其他位要全部包含0到(最低位-1)的所有数,否则必须通过进位来取到不包含的数,然后在考虑除最低位以外的数在(最低位+1)到(p-1)中最大的不存在的数,这是计算的边界,因为n<=100,所以不需要考虑时间问题,暴力即可

    如果进位,那么先把要进位的数按运算法则运算,得到最终的进位后的数,如果都是(p-1),进位后会在最高位前面多出一个1,运算的时候也要存下出现过的数,最后就是最低位置为0,然后暴力查找最大的没表示到的数,暴力查找时,因为大于等于最低位的数都在进位时遍历过了,所以直接从(最低位-1)开始暴力的遍历即可

    AC代码:

    1. /*##########################################################
    2. # File Name: 1.cpp
    3. # Author: HideInTheSea
    4. # Created Time: 2022年11月23日 星期三 18时43分30秒
    5. ##########################################################*/
    6. #include
    7. using namespace std;
    8. using LL = long long;
    9. void Solve() {
    10. int n, p;
    11. cin >> n >> p;
    12. vector<int> a(n + 1);
    13. map<int, int> mp;
    14. for (int i = 1; i <= n; i++) {
    15. cin >> a[i];
    16. mp[a[i]] = 1;
    17. }
    18. if (mp.size() == p) {
    19. cout << "0\n";
    20. return;
    21. }
    22. function<bool(int, int)> check = [&](int x, int y) {
    23. for (int i = x; i <= y; i++) {
    24. if (mp.count(i) == 0) {
    25. return false;
    26. }
    27. }
    28. return true;
    29. };
    30. function<int(int, int)> check1 = [&](int x, int y) {
    31. for (int i = y; i > x; i--) {
    32. if (mp.count(i) == 0) {
    33. return i;
    34. }
    35. }
    36. return x;
    37. };
    38. int maxx = check1(a[n] + 1, p - 1);
    39. if (check(0, a[n])) {
    40. if (maxx == a[n]) {
    41. cout << p - a[n] - 1 << '\n';
    42. } else {
    43. cout << maxx - a[n] << '\n';
    44. }
    45. } else {
    46. LL ans = p - a[n];
    47. int x = a[n];
    48. a[n] = 0;
    49. mp[a[n]] = 1;
    50. for (int i = n - 1; i >= 0; i--) {
    51. a[i]++;
    52. if (a[i] == p) {
    53. a[i] = 0;
    54. } else {
    55. mp[a[i]] = 1;
    56. break;
    57. }
    58. }
    59. function<int(int, int)> calc = [&](int x, int y) {
    60. for (int i = y - 1; i >= x; i--) {
    61. if (mp.count(i) == 0) {
    62. return i;
    63. }
    64. }
    65. return 0;
    66. };
    67. cout << ans + calc(0, x) << '\n';
    68. }
    69. }
    70. int main() {
    71. ios::sync_with_stdio(false);
    72. cin.tie(nullptr);
    73. int T;
    74. cin >> T;
    75. while (T--) {
    76. Solve();
    77. }
    78. return 0;
    79. }

    G. Restore the Permutation

    看到题,首先考虑贪心的把越小的数越要放到前面,然后根据题目的描述得知,给出的数组中的数是相邻两个数之间最大的数,因此要把这个数放到第二个位置,这样才能保证字典序最小

    根据样例能够看出,如果一个数出现了两次,或者出现的无论如何都没法组成全排列的话就输出-1

    再进行构造答案,首先根据字典序,标号小的一定要往前放,再考虑b中的数是相邻两个数之间最大的数,那么要尽可能地让他俩之差小,这样标号小地数才能够尽可能的往前放,在遍历的时候应该从标号大的数递减遍历,这样能够让没在b中出现的相对比较大的数放在靠后的位置,如果一个数在b中出现过,就把该数下标放到堆里,这样既能保证b中的数是相邻两个数之间最大的,也能保证两个数之差最小,这样才能使得最后的全排列字典序最小

    AC代码:

    1. /*##########################################################
    2. # File Name: 2.cpp
    3. # Author: HideInTheSea
    4. # Created Time: 2022年11月22日 星期二 20时43分24秒
    5. ##########################################################*/
    6. #include
    7. using namespace std;
    8. using LL = long long;
    9. void Solve() {
    10. int n;
    11. cin >> n;
    12. vector<int> a(n + 1), b(n + 1);
    13. bool ok = true;
    14. for (int i = 2; i <= n; i += 2) {
    15. cin >> a[i];
    16. b[a[i]] = i;
    17. }
    18. priority_queue<int> q;
    19. for (int i = n; i >= 1; i--) {
    20. if (!b[i]) {
    21. if (q.empty()) {
    22. ok = false;
    23. break;
    24. } else {
    25. a[q.top() - 1] = i;
    26. q.pop();
    27. }
    28. } else {
    29. q.push(b[i]);
    30. }
    31. }
    32. if (!ok) {
    33. cout << "-1\n";
    34. } else {
    35. for (int i = 1; i <= n; i++) {
    36. cout << a[i] << " \n"[i == n];
    37. }
    38. }
    39. }
    40. int main() {
    41. ios::sync_with_stdio(false);
    42. cin.tie(nullptr);
    43. int T;
    44. cin >> T;
    45. while (T--) {
    46. Solve();
    47. }
    48. return 0;
    49. }

  • 相关阅读:
    Visual Paradigm 里什么是复合结构图?
    leetcode做题笔记133. 克隆图
    哈希表— —链式实现
    SpringMVC(一、快速入门)
    综合布线 子网掩码 IP地址 子网划分
    使用线段树解决数组任意区间元素修改问题
    剑指 Offer 46. 把数字翻译成字符串(DP)
    MATLAB基础学习笔记
    详解图(性质,结构,遍历,最小生成树,最短路径)
    阿里云短信服务接入流程
  • 原文地址:https://blog.csdn.net/eyuhaobanga/article/details/127988585