Educational Codeforces Round 69 (Rated for Div. 2)

本文最后更新于:星期四, 二月 3日 2022, 9:15 晚上

A. DIY Wooden Ladder

签到。

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

#include <bits/stdc++.h>

using namespace std;

#define N 100010

int n;
int a[N];

int main() {
// freopen("input.txt", "r", stdin);
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
sort(a + 1, a + 1 + n);
int ans = n - 2;
ans = min(ans, a[n] - 1);
ans = min(ans, a[n - 1] - 1);
printf("%d\n", ans);
}
return 0;
}

B.Pillars

题意:有nn根柱子,每根柱子上有一个磁盘,每个磁盘都有自己的半径,第ii根柱子上的磁盘能移动到第jj根柱子上的前提是:

  • iijj相邻
  • ii根柱子上只有一个磁盘
  • jj根柱子没有磁盘或者顶部磁盘半径大于第ii根柱子

问能否将所有磁盘移动到一根柱子上。

思路:很显然只能先递增后递减的形式。

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

#include <bits/stdc++.h>

using namespace std;

#define N 200010

int n;
int a[N];

bool solve() {
int Max = 0, pos = 0;
for (int i = 1; i <= n; ++i) {
if (a[i] > Max) {
Max = a[i];
pos = i;
}
}
for (int i = 2; i <= pos; ++i) {
if (a[i] < a[i - 1]) {
return false;
}
}
for (int i = pos; i < n; ++i) {
if (a[i + 1] > a[i]) {
return false;
}
}
return true;
}

int main() {
// freopen("input.txt", "r", stdin);
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
puts(solve() ? "YES" : "NO");
}
return 0;
}

C.Array Splitting

题意:有一个长度为nn的序列aa,将序列分成kk段,使得i=1k(max(i)min(i))\sum_{i=1}^{k}(max(i)-min(i))最小,其中max(i)max(i)表示第ii段最大值,min(i)min(i)表示第ii段最小值,且保证aia_i非降序。

思路:$\sum_{i=1}^k (max(i)-min(i))=a_n-a_1+\sum_{i=1}^{k-1} a_{b_i}-a_{b_i+1} 其中b_i表示第i段末尾下标,很显然贪心选取k-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

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
#define INF 0x3f3f3f
#define N 300010

int n, k;
ll a[N];
vector<ll> vec;

int main() {
// freopen("input.txt", "r", stdin);
while (scanf("%d %d", &n, &k) != EOF) {
vec.clear();
for (int i = 1; i <= n; ++i) {
scanf("%lld", a + i);
if (i != 1) {
vec.push_back(a[i] - a[i - 1]);
}
}
sort(vec.begin(), vec.end());
ll ans = a[n] - a[1];
for (int len = vec.size(), i = len - 1; i >= len - k + 1; --i) {
ans -= vec[i];
}
printf("%lld\n", ans);
}
return 0;
}

D.Yet Another Subarray Problem

题意:给出一个长度为nn的序列aa,以及m,km,k,求i=lraikrl+1m\sum_{i=l}^{r}a_i-k\lceil \frac{r-l+1}{m}\rceil的最大值

思路:dp[i]dp[i]表示到ii节点作为末尾的最大值,对于每个节点ii很显然只能选取ii前面不到mm个数,或者选满mm个数后再加上dp[im]dp[i-m],由此转移下去去中间值最大值即可。

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

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
#define INF 0x3f3f3f
#define N 300010

int n, m, k;
ll a[N];
ll dp[N];
ll ans;


int main() {
// freopen("input.txt", "r", stdin);
while (scanf("%d %d %d", &n, &m, &k) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%lld", a + i);
}
memset(dp, 0, sizeof dp);
ans = 0;
for (int i = 1; i <= n; ++i) {
ll Max = a[i], sum = 0;
for (int j = i; j >= 1 && j >= i - m + 1; --j) {
sum += a[j];
Max = max(Max, sum);
}
dp[i] = max(dp[i], max(Max - k, sum - k + dp[max(i - m, 0)]));
ans = max(ans, dp[i]);
}
printf("%lld\n", ans);
}
return 0;
}

E.Culture Code

题意:有nn个俄罗斯套娃,每个套娃有两个属性in,out(out>in)in,out(out>in),套娃ii能放在jj对的前提是outi<=injout_i<=in_j

  • 定义一组套娃的额外空间为ini1+(ini2outi1)+(ini3outi2)++(inikoutik1)in_{i_1}+(in_{i_2}-out_{i_1})+(in_{i_3}-out_{i_2})+\cdots+(in_{i_k}-out_{i_{k-1}}),其中i1,i2,,iki_1,i_2,\cdots,i_k为这组套娃的下标。
  • 定义一组套娃是个极大套娃组:当且仅当不能再有另外一个套娃套在他们身上了。

询问有多少种极大套娃组的额外空间最小

思路:f[i]f[i]表示使用ii的最小额外空间,g[i]g[i]为使用ii的方案数。对于每个套娃,比它大的最小的俄罗斯套娃。如果和i+1i+1套娃的额外空间相同,则加上i+1i+1的方案数,如果比i+1i+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

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<ll, ll> pll;

#define INFLL 0x3f3f3f3f3f3f3f
#define N 400010

const ll p = (ll) 1e9 + 7;


int n;
pll a[N];
ll f[N], g[N];

void add(ll &x, ll y) {
x += y;
if (x >= p) {
x -= p;
}
}

int main() {
// freopen("input.txt", "r", stdin);
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%lld %lld", &a[i].second, &a[i].first);
}
sort(a + 1, a + 1 + n);
f[n + 1] = INFLL;
for (int i = n; i >= 1; --i) {
int pos = lower_bound(a + i, a + 1 + n, pll(a[i].second, -1)) - a;
if (pos == n + 1) {
f[i] = a[i].first;
g[i] = 1ll;
} else {
f[i] = a[i].first - a[i].second + f[pos];
g[i] = g[pos];
}
if (f[i] == f[i + 1]) {
add(g[i], g[i + 1]);
} else if (f[i] > f[i + 1]) {
f[i] = f[i + 1];
g[i] = g[i + 1];
}
}
printf("%lld\n", g[1]);
}
return 0;
}