J 砍竹子

砍竹子

【问题描述】
这天,小明在砍竹子,他面前有 n 棵竹子排成一排,一开始第 i 棵竹子的高度为 hi .

他觉得一棵一棵砍太慢了,决定使用魔法来砍竹子。魔法可以对连续的一段相同高度的竹子使用,假设这一段竹子的高度为 H,那么使用一次魔法可以把这一段竹子的高度都变为 [ sqrt( [H / 2] + 1 ) ] ,其中 [x] 表示对 x 向下取整。小明想知道他最少使用多少次魔法可以让所有的竹子的高度都变为 1。

【输入格式】
第一行为一个正整数n,表示竹子的棵数。
第二行共n个空格分开的正整数h,表示每棵竹子的高度。

【输出格式】
一个整数表示答案。

【样例输入】
6
2 1 4 2 6 7
1
2

【样例输出】
5
1

【样例说明】
其中一种方案: 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步完成

【评测用例规模与约定】

对于20%的数据,保证 n ≤ 1000, hi ≤ 10^6。
对于100%的数据,保证 n ≤ 2 × 10^5, hi ≤ 10^18。

题解

思路:
在这里插入图片描述
如图,首先,1e18的高度也最多只要砍6下,用m维护单个竹子最多砍几下,res则是若一棵一棵砍总共砍多少下,然后每一个用栈然后保存到数组中,即每个结点保存每棵树被砍到1会经历的高度,且随着数组中随着下标增大而增大,即上图中结点下面的部分是高度较低的,然后如果高度是相同的必在同一结点深度,但在同一结点深度不一定高度相同,判断再用res减去即可。

注意:本题是longlong,用sqrt精度不够,要用sqrtl

另:关于sqrt函数
sqrtf() 返回效率更高,精度最低
sqrt() 最常用,返回效率中等,精度中等
sqrtl() 返回效率较低,精度最高

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[200006][10];
ll magic(ll x)
{
  return sqrtl(x/2+1);
}
int main()
{
  ll n,res=0,m=0;
  cin>>n;
  ll stk[10];
  for(int i=0;i<n;i++)
  {
    ll x;
    scanf("%lld",&x);
    ll top=0;
    while(x>1) 
    {
      stk[++top]=x;
      x=magic(x);
    }
    for(int j=0,k=top;k>0;j++,k--) a[i][j]=stk[k];
    res+=top;
    m=max(m,top);
  }
  for(int i=0;i<m;i++)
  {
    for(int j=1;j<n;j++)
    {
      if(a[j][i]>0&&a[j][i]==a[j-1][i]) res--;
    }
  }
  cout<<res<<endl;
  return 0;
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值