当前位置:   article > 正文

2040: [蓝桥杯2022初赛] 砍竹子(优先队列)_这天,小明在砍竹子,他面前有 nn 棵竹子排成一排,一开始第 ii 棵竹子的高度为 h_{i

这天,小明在砍竹子,他面前有 nn 棵竹子排成一排,一开始第 ii 棵竹子的高度为 h_{i

2040: [蓝桥杯2022初赛] 砍竹子

内存限制:256 MB 时间限制:1 S 标准输入输出

题目类型:传统 评测方式:文本比较 上传者:外部导入

提交:137 通过:60

题目描述

这天,小明在砍竹子,他面前有 n 棵竹子排成一排,一开始第 i 棵竹子的高度为 hi.
他觉得一棵一棵砍太慢了,决定使用魔法来砍竹子。
魔法可以对连续的一段相同高度的竹子使用,假设这一段竹子的高度为H,
那么使用一次魔法可以把这一段竹子的高度都变为:

其中 ⌊x⌋ 表示对 x 向下取整

小明想知道他最少使用多少次魔法可以让所有的竹子的高度都变为1。

输入格式

第一行为一个正整数 n,表示竹子的棵数。
第二行共 n 个空格分开的正整数 hi,表示每棵竹子的高度。
20%的测试数据:n ≤ 1000; hi ≤ 10^6。
100%的测试数据:n ≤ 2 × 10^5; hi ≤ 10^18。

输出格式

一个整数表示答案。

输入样例 复制

  1. 6
  2. 2 1 4 2 6 7

输出样例 复制

5

数据范围与提示

其中一种方案:
2 1 4 2 6 7
→ 2 1 4 2 6 2
→ 2 1 4 2 2 2
→ 2 1 1 2 2 2
→ 1 1 1 2 2 2
→ 1 1 1 1 1 1
共需要 5 步完成。

 1)结构体实现的优先队列

  1. /**
  2. 1)结构体实现的优先队列
  3. */
  4. /**
  5. #include <iostream>
  6. #include <vector>
  7. #include <queue>
  8. #include <algorithm>
  9. #include <cstdio>
  10. #include <cmath>
  11. #include <functional>
  12. using namespace std;
  13. typedef long long LL;
  14. //可以在定义结构体(类)的时候就重载运算符,当然当重载的运算符是成员函数时,成员函数
  15. //的(显示)参数数量比运算对象的数量少一个,this绑定到左侧运算对象;
  16. //当不是成员函数的时候,要定义成友元函数,即在函数前加关键字 friend ,此时友元函数的参数
  17. //和一般函数的数量一样
  18. struct infor
  19. {
  20. LL val;
  21. int pos;
  22. // friend bool operator < (const infor &a,const infor &b) //非成员函数需要将其定义成友元函数函数
  23. // {
  24. // if(a.val!=b.val)
  25. // return a.val<b.val;
  26. // else
  27. // return a.pos<b.pos;
  28. // }
  29. };
  30. struct cmp
  31. {
  32. bool operator () (const infor &a,const infor &b)
  33. {
  34. if(a.val!=b.val)
  35. return a.val<b.val;
  36. else
  37. return a.pos<b.pos;
  38. }
  39. };
  40. int main()
  41. {
  42. int n;
  43. infor val;
  44. // priority_queue<infor> vec;
  45. priority_queue<infor,vector<infor> ,cmp> vec;
  46. scanf("%d",&n);
  47. for(int i=0;i<n;++i)
  48. {
  49. scanf("%lld",&val.val);
  50. val.pos=i;
  51. vec.push(val);
  52. }
  53. int sum=0;
  54. while(vec.top().val!=1)
  55. {
  56. infor top=vec.top();
  57. vec.pop();
  58. LL ans=floor(sqrt((top.val/2+1)*1.0));
  59. vec.push({ans,top.pos});
  60. int coun=1;
  61. while(vec.top().val==top.val&&vec.top().pos==top.pos-coun++)
  62. {
  63. infor temp=vec.top();
  64. vec.pop();
  65. vec.push({ans,temp.pos});
  66. }
  67. ++sum;
  68. }
  69. cout << sum << endl;
  70. return 0;
  71. }
  72. */

 

 2) pair 容器实现的优先队列
    优先队列的优先级默认设置为数字大的优先级高

  1. /**
  2. 2) pair 容器实现的优先队列
  3. 优先队列的优先级默认设置为数字大的优先级高
  4. */
  5. /**
  6. #include <iostream>
  7. #include <vector>
  8. #include <queue>
  9. #include <algorithm>
  10. #include <cstdio>
  11. #include <cmath>
  12. using namespace std;
  13. typedef pair<long long ,int> pll;
  14. int main()
  15. {
  16. int n;
  17. pll val;
  18. priority_queue<pll> vec;
  19. scanf("%d",&n);
  20. for(int i=0;i<n;++i)
  21. {
  22. scanf("%lld",&val.first);
  23. val.second=i;
  24. if(val.first!=1)
  25. vec.push(val);
  26. }
  27. int sum=0;
  28. while(!vec.empty()&&vec.top().first!=1)
  29. {
  30. pll top=vec.top();
  31. vec.pop();
  32. long long ans=floor(sqrt((top.first/2+1)*1.0));
  33. if(ans!=1)
  34. vec.push({ans,top.second});
  35. int coun=1;
  36. while(!vec.empty()&&vec.top().first==top.first&&vec.top().second==top.second-coun++)
  37. {
  38. pll temp=vec.top();
  39. vec.pop();
  40. if(ans!=1)
  41. vec.push({ans,temp.second});
  42. }
  43. ++sum;
  44. }
  45. cout << sum << endl;
  46. return 0;
  47. }*/

3) 先把一棵树砍掉所需要的次数累加起来,然后再减掉相邻相等的树;
    把每棵树每次砍掉之前的高度记录下来,由于是200000棵树,1e18高度的树
    砍到1的次数为6,因此可以开一个dp[500010][6]的数组来存储数据。

  1. /**
  2. 3) 先把一棵树砍掉所需要的次数累加起来,然后再减掉相邻相等的树;
  3. 把每棵树每次砍掉之前的高度记录下来,由于是200000棵树,1e18高度的树
  4. 砍到1的次数为6,因此可以开一个dp[500010][6]的数组来存储数据。
  5. */
  6. #include <iostream>
  7. #include <vector>
  8. #include <queue>
  9. #include <algorithm>
  10. #include <cstdio>
  11. #include <cmath>
  12. using namespace std;
  13. typedef long long LL;
  14. const int maxn=200010,m=10;
  15. LL dp[maxn][m];
  16. int main()
  17. {
  18. int n;
  19. scanf("%d",&n);
  20. LL sta[m],val,res=0;
  21. int ans=0;
  22. for(int i=0;i<n;++i)
  23. {
  24. int top=0;
  25. scanf("%lld",&val);
  26. while(val>1) sta[++top]=val,val=sqrt(val/2+1);
  27. ans=max(ans,top);
  28. res+=top;
  29. for(int j=0;top>0;++j,--top)
  30. dp[i][j]=sta[top];
  31. }
  32. for(int i=0;i<ans;++i)
  33. for(int j=0;j<n-1;++j)
  34. {
  35. if(dp[j][i]&&dp[j][i]==dp[j+1][i]) //为什么此处只需要判断dp[j][i]>=1便可,因为dp[j][[i]
  36. res--; //最小的值都是2
  37. }
  38. cout << res << endl;
  39. return 0;
  40. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/388664
推荐阅读
相关标签
  

闽ICP备14008679号