题目描述
这天,小明在砍竹子,他面前有 n n n 棵竹子排成一排,一开始第 i i i 棵竹子的高度为 h i h_{i} hi.
他觉得一棵一棵砍太慢了,决定使用魔法来砍竹子。魔法可以对连续的一段相同高度的竹子使用,假设这一段竹子的高度为 H H H,那么使用一次魔法可以把这一段竹子的高度都变为 ⌊ ⌊ H 2 ⌋ + 1 ⌋ \left\lfloor\sqrt{\left\lfloor\frac{H}{2}\right\rfloor+1}\right\rfloor ⌊⌊2H⌋+1⌋, 其中 ⌊ x ⌋ \lfloor x\rfloor ⌊x⌋ 表示对 x x x 向下取整。小明想知道他最少使用多少次魔法可以让所有的竹子的高度都变为 1 1 1。
输入格式
第一行为一个正整数 n n n,表示竹子的棵数。
第二行共 n n n 个空格分开的正整数 h i h_{i} hi,表示每棵竹子的高度。
输出格式
一个整数表示答案。
样例 #1
样例输入 #1
6
2 1 4 2 6 7
样例输出 #1
5
提示
【样例说明】
其中一种方案:
214267 → 214262 → 214222 → 211222 → 111222 → 111111 214267\rightarrow 214262\rightarrow 214222\rightarrow 211222\rightarrow 111222\rightarrow 111111 214267→214262→214222→211222→111222→111111
共需要 5 步完成
【评测用例规模与约定】
对于 20 % 20 \% 20% 的数据,保证 n ≤ 1000 , h i ≤ 1 0 6 n \leq 1000, h_{i} \leq 10^{6} n≤1000,hi≤106 。
对于 100 % 100 \% 100% 的数据,保证 n ≤ 2 × 1 0 5 , h i ≤ 1 0 18 n \leq 2 \times 10^{5}, h_{i} \leq 10^{18} n≤2×105,hi≤1018 。
蓝桥杯 2022 省赛 B 组 J 题。
解析
显然根据贪心,需要先砍高的竹子以便于凑“魔法”,所以遍历计算出每棵竹子应该砍伐的次数,然后不断砍次数最高的竹子
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N=2e5+5;
int n;
int a[N],cnt[N];
int check(int x){
return (int)sqrt(x/2+1);
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
int x=a[i];
while(x!=1){
cnt[i]++;
x=check(x);
}
}
int ans=0,maxx=*max_element(cnt+1,cnt+n+1);
for(int i=maxx;i>0;i--){
for(int j=1;j<=n;j++){
if(cnt[j]==i){
if(a[j]!=a[j+1]) ans++;
cnt[j]--;
a[j]=check(a[j]);
}
}
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t=1;
// cin>>t;
while(t--) solve();
return 0;
}