蓝桥杯——砍竹子

336 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第35天,点击查看活动详情

[蓝桥杯 2022 省 B] 砍竹子

题目描述

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

他觉得一棵一棵砍太慢了,决定使用魔法来砍竹子。魔法可以对连续的一段相同高度的竹子使用,假设这一段竹子的高度为 HH,那么使用一次魔法可以把这一段竹子的高度都变为 H2+1\left\lfloor\sqrt{\left\lfloor\frac{H}{2}\right\rfloor+1}\right\rfloor, 其中 x\lfloor x\rfloor 表示对 xx 向下取整。小明想知道他最少使用多少次魔法可以让所有的竹子的高度都变为 11

输入格式

第一行为一个正整数 nn,表示竹子的棵数。

第二行共 nn 个空格分开的正整数 hih_{i},表示每棵竹子的高度。

输出格式

一个整数表示答案。

样例 #1

样例输入 #1

6
2 1 4 2 6 7

样例输出 #1

5

提示

【样例说明】

其中一种方案:

214267214262214222211222111222111111214267\rightarrow 214262\rightarrow 214222\rightarrow 211222\rightarrow 111222\rightarrow 111111

共需要 5 步完成

【评测用例规模与约定】

对于 20%20 \% 的数据,保证 n1000,hi106n \leq 1000, h_{i} \leq 10^{6}

对于 100%100 \% 的数据,保证 n2×105,hi1018n \leq 2 \times 10^{5}, h_{i} \leq 10^{18}

蓝桥杯 2022 省赛 B 组 J 题。

分析

这题是一个贪心题,暴力肯定过不去,用堆的话,时间复杂度比较吃紧,我们想到把一根竹子变成1最多只要操作6次,所以可以把每一根竹子的每一段都存下来,然后看看相邻一段有没有相等的有,次数就--就ok了

代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int N=2e5+10;
const int M=10;
#define ll long long
ll a[N];
ll f[N][M];
ll stk[N];
int main(){
	int n;
	cin>>n;
	ll res=0;
	int maxn=-1;
	for(int i=1;i<=n;i++){
		ll x;
		cin>>x;
		int top=0;
		while(x>1){
			stk[++top]=x;
			x=sqrtl(x/2+1);
		}
		res+=top;
		maxn=max(maxn,top);
		for(int j=1,k=top;k;j++,k--){
			f[i][j]=stk[k];
		}
	}
	for(int i=2;i<=n;i++){
		for(int j=1;j<=maxn;j++){
			if(f[i][j] && f[i][j]==f[i-1][j]){
				res--;
			}
		}
	}
	cout<<res<<endl;
	return 0;
}

希望能帮助到大家,qaq!