P4343 题解


Problem Link

这一道二分,非常的经典(

首先,可以在 的时间内,计算出定值 对应切了多少道题目。

那么就可以二分 ,每次 check 计算出的 与原 的大小关系,并由此二分。

上下界之间只有一个等号的不同,是一样的(

坑点:

  1. 输出 -1 只用一个。
  2. long long
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Copyright 2022 Lotuses
#include <cstdio>
#include <cstring>
#include <vector>

#define int long long

#define gc getchar()
template<typename T>
void read(T &r) { // NOLINT
r = 0; static char ch, last; // NOLINT
ch = gc, last = 'z';
while (ch < '0' || ch > '9') last = ch, ch = gc;
while (ch >= '0' && ch <= '9') r = (r << 1) + (r << 3) + (ch ^ 48), ch = gc;
r = (last == '-') ? -r : r;
}

template<typename T, typename...Ts>
void read(T &arg, Ts&...arg_left) { // NOLINT
read(arg);
read(arg_left...);
}

int m, k;
int a[114514];

int check(int n) {
int word = 0, cnt = 0;
for (int i = 0; i < m; i++) {
word += a[i];
word = word < 0 ? 0 : word;
if (word >= n) {
word = 0;
cnt++;
}
}
return cnt;
}

int div1() {
int l = 1, r = 100005ll * 1000000009ll;
while (l + 10 < r) {
int mid = (l + r) >> 1;
int nowk = check(mid);
// printf("check %d\n", nowk);
if (nowk <= k) {
r = mid;
} else {
l = mid;
}
// printf("debug %d %d\n", l, r);
}
int i;
for (i = l; i <= r; i++) {
int nowk = check(i);
if (nowk == k) break;
}
if (check(i) != k) return -1;
return i;
}

int div2() {
int l = 1, r = 100005ll * 1000000009ll;
while (l + 10 < r) {
int mid = (l + r) >> 1;
int nowk = check(mid);
if (nowk < k) {
r = mid;
} else {
l = mid;
}
}
int i;
for (i = r; i >= l; i--) {
int nowk = check(i);
if (nowk == k) break;
}
if (check(i) != k) return -1;
return i;
}

signed main() {
read(m, k);
for (int i = 0; i < m; i++) {
read(a[i]);
}

int ans1 = div1(),
ans2 = div2();

if (ans1 == -1 || ans2 == -1) {
puts("-1");
return 0;
}

printf("%lld %lld\n", ans1, ans2);
return 0;
}