【题目描述】
这天,小明在砍竹子,他面前有 n 棵竹子排成一排,一开始第 i 棵竹子的高度为 hi。
他觉得一棵一棵砍太慢了,决定使用魔法来砍竹子。
魔法可以对连续的一段相同高度的竹子使用,假设这一段竹子的高度为 H,那么使用一次魔法可以把这一段竹子的高度都变为
其中 ⌊x⌋ 表示对 x 向下取整。小明想知道他最少使用多少次魔法可以让所有的竹子的高度都变为 1。
【输入格式】
第一行为一个正整数 n,表示竹子的棵数。
第二行共 n 个空格分开的正整数 hi,表示每棵竹子的高度。
【输出格式】
一个整数表示答案。
【数据范围】
对于 20% 的数据,保证 1≤n≤1000,1≤hi≤10的6次方。
对于 100% 的数据,保证 1≤n≤2×10的5次方,1≤hi≤10的18次方。
【输入样例】
6
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 步完成。
【代码】
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int N = 200010, M = 20;
int n, m;
LL f[N][M];
int main()
{
scanf("%d", &n);
LL stk[M];
int res = 0;
for (int i = 0; i < n; i ++ )
{
LL x;
int top = 0;
scanf("%lld", &x);
while (x > 1) stk[ ++ top] = x, x = sqrtl(x / 2 + 1);
res += top;
m = max(m, top);
for (int j = 0, k = top; k; j ++, k -- )
f[i][j] = stk[k];
}
for (int i = 0; i < m; i ++ )
for (int j = 1; j < n; j ++ )
if (f[j][i] && f[j][i] == f[j - 1][i])
res -- ;
printf("%d\n", res);
return 0;
}