CF 1661C Water the Trees(思维)

本文最后更新于:3 years ago

题目链接:点击跳转

题意: 公园里有N棵树,在奇数天浇水可以使树的高度+1,偶数天+2(每天只能浇一次水,可以选择不浇),问最少需要多少天,能使得所有树的高度一致。

思路:

  • 如果当前树与最高的那棵树的高度差为奇数,那么就意味着该树至少要占用一次奇数天(只能多,不能少),而其他的均可通过偶数天完成。
  • 若偶数天如果大于奇数天,那么可以通过将一个偶数天拆成2个奇数天来减少时间。
  • 为保持奇数偶数尽量相等(使天数尽可能少),可以将偶数多出的天数的1/3转化为奇数天,如果存在余数,若余数为1,如果转化,则需要两个1天,花费3天,而不转化,只需要2天。若余数为2,则不转化为4天,转化为3天。
  • 这样求出来的并不一定是最优解,因为存在奇数大于偶数的情况,所有可以通过将最大值加1,这样子就把奇数的差值转为偶数,偶数的差值转为奇数,在进行求解,取两次中的较小值输出即可。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include<bits/stdc++.h>
#include <ostream>

using namespace std;
typedef long long ll;
#define endl '\n'
typedef pair<int, int> PII;
#define debug() cout.flush()
#define for0(i, a) for (int i = 0; i < a; ++i)
#define REP(i, a, b) for (int i = a; i < b; ++i)
#define FOR(i, a, b) for (int i = a; i <= b; ++i)
#define REPC(i, a, b, c) for (ll i = a; i < b && i < c; ++i)
#define RREP(i, a, b) for (int i = a; i >= b; --i)
const ll MOD = 1e9 + 7;
const ll mod = 998244353;
const int INF = 0x3f3f3f3f;
const int MAXN = 3e5 + 5e2;

inline void init() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}

int n;
ll h[MAXN];

inline ll check(ll maxn) {
ll res = 0;
ll odd = 0, even = 0;
for0 (i, n) {
if (maxn - h[i] & 1) {
odd++;
}
even += (maxn - h[i]) / 2;
}
if (even > odd) {
ll sub = (even - odd + 1) / 3;
odd += sub * 2;
even -= sub;
}
ll sub = min(even, odd);
res = sub * 2;
odd -= sub;
even -= sub;
if (odd) res += odd * 2 - 1;
else if (even) res += even * 2;
return res;
}

inline void solve() {
int maxn = -1;
for0 (i, n) {
cin >> h[i];
maxn = maxn > h[i] ? maxn : h[i];
}
cout << min(check(maxn), check(maxn + 1)) << endl;
}

signed main() {
init();
int _;
cin >> _;
while (_--) {
cin >> n;
solve();
}
return 0;
}