砍竹子
【问题描述】
这天,小明在砍竹子,他面前有 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;
}