#include<iostream>
#include<queue>
#include<math.h>
using namespace std;
long long res;
struct node
{
long long val,l, r;
};
bool operator <(node a, node b)
{
return a.val == b.val ? a.l < b.l : a.val < b.val;//定义调堆的规则,如果值相等的情况下,优先考虑左区间大的
}
int main(void)
{
long long n, k;
priority_queue<node>p;//定义一个node类型的堆
scanf("%lld", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &k);
p.push({ k,i,i });
}
while (p.top().val != 1)
{
node t = p.top();//取出当前的堆顶元素(最大值)
p.pop();//先将最大值出堆,等砍掉之后还会将高度重新入堆
node top;//用于等会记录堆中第二大的值
while (!p.empty())
{
top = p.top();//堆中第二大的值
if (t.val == top.val && t.l - 1 == top.r)//如果最大值和第二大的值相等,并且区间差只有1,就是相邻的竹子
{
p.pop();//一起砍掉,就是先pop掉第二大的,所有相等的且相邻的只用保留一个数就行了,当这个数被砍为1的时候相当于所有相邻的都被砍为1了
t.l = top.l;//相当于合并区间了
}
else
{
break;//如果没有可以一并砍掉的就直接跳出循环
}
}
int val = sqrtl(t.val / 2 + 1);//计算
p.push({ val,t.l,t.r });//将砍了之后的高度加入堆中
res++;//砍的次数+1
}
printf("%lld", res);
return 0;
}