【洛谷】P8787 [蓝桥杯 2022 省 B] 砍竹子 的题解
题目传送门
思路
这个题有两个做法,一种是用 set 或者堆来维护一个高度到区间的映射,另一个用并查集维护区间。
这个题本质是一个最长公共下降子序列的问题,对于任意一个 h h h,只要它高度降到了与前一个高度下降过程中的公共值,那么它就不需要花费代价继续下降。如果它降得的当前高度与前一个高度没有公共值,则需要多花费一个代价,来降低自己的高度。我们只需要开两个数组暴力做一下就行。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <climits>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <ctime>
#include <string>
#include <cstring>
#define lowbit(x) x & (-x)
#define endl "\n"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace fastIO {
inline int read() {
register int x = 0, f = 1;
register char c = getchar();
while (c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
}
using namespace fastIO;
ll a[200005];
vector <ll> b[200005];
int n;
ll solve(ll x) {
return sqrt(x / 2 + 1);
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> a[i];
int res = 0;
for(int i = 1; i <= n; i ++) {
while(a[i] > 1) {
int flag = 0;
for(ll j : b[i - 1]) {
if(a[i] == j) {
flag = 1;
break;
}
}
if(!flag) res ++;
b[i].push_back(a[i]);
a[i] = solve(a[i]);
}
}
cout << res;
return 0;
}