Contest Info


[Practice Link](https://codeforc.es/contest/1197)

Solved A B C D E F
5/6 O O O O Ø -
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. DIY Wooden Ladder

签到题。

#include <bits/stdc++.h>
using namespace std; #define N 100010
int n, a[N]; int main() {
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 res = 0;
for (int i = 2; i < n; ++i) {
res = max(res, min(a[i] - 1, i - 1));
}
printf("%d\n", res);
}
return 0;
}

B. Pillars

题意:

有\(n\)根柱子,每根柱子上有一个磁盘,一个磁盘能从第\(i\)根柱子移动到第\(j\)根柱子的前提是:

  • 第\(j\)根柱子上没有磁盘
  • 或者第\(i\)根柱子上的磁盘半径颜色小于第\(j\)根柱子的磁盘

    现在给出每根柱子上磁盘的半径,问能够存在一种方案使得将所有的磁盘都移动的一根柱子上

思路:

考虑假设能将所有磁盘移动到一根柱子上,那么最终肯定是移动到初始磁盘半径最大的那根柱子上。

那么考虑从这个柱子开始,每次往两边扩展,取大的贪心往这根柱子上移动。

如果不能移动就是不行。

因为考虑最后那根柱子上的磁盘半径肯定是递增的,所以不可能存在跨越移动的情况。

代码:

#include <bits/stdc++.h>
using namespace std; #define N 200010
int n, a[N]; int main() {
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; ++i) scanf("%d", a + i);
int pos = 1;
for (int i = 2; i <= n; ++i) {
if (a[i] > a[pos]) pos = i;
}
int l = pos - 1, r = pos + 1;
bool F = 1;
int lst = a[pos];
while (l >= 1 || r <= n) {
if (l < 1) {
if (a[r] >= lst) {
F = 0;
break;
}
lst = a[r];
++r;
} else if (r > n) {
if (a[l] >= lst) {
F = 0;
break;
}
lst = a[l];
--l;
} else {
if (a[l] > a[r]) {
if (a[l] >= lst) {
F = 0;
break;
}
lst = a[l];
--l;
} else {
if (a[r] >= lst) {
F = 0;
break;
}
lst = a[r];
++r;
}
}
}
puts(F ? "YES" : "NO");
}
return 0;
}

C. Array Splitting

题意:

有一个长度为\(n\)的序列\(a_i\),要将序列分成\(k\)段,使得下式最小:

\[\begin{eqnarray*}
\sum\limits_{i = 1}^k (max(i) - min(i))
\end{eqnarray*}
\]

其中\(max(i)\)表示第\(i\)段中最大的数,\(min(i)\)表示第\(i\)段中最小的数,保证\(a_i\)是单调非降序的。

思路:

考虑\(a_i\)是单调非降的,那么\(max(i) - min(i)\)这个东西肯定是区间的末尾减去区间的开头,那么注意到区间的末尾的下一个数即为下一个区间的开头,变换式子有:

\[\begin{eqnarray*}
a_n - a_1 + \sum\limits_{i = 1}^{k - 1} a_{b_i} - a_{b_i + 1}
\end{eqnarray*}
\]

其中\(b_i\)表示第\(i\)段末尾的下标。

然后这个东西用堆维护一下,贪心取\(k - 1\)个即可。

代码:

#include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 300010
int n, k, a[N]; int main() {
while (scanf("%d%d", &n, &k) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
ll res = a[n] - a[1];
vector <int> vec;
for (int i = 1; i < n; ++i) {
vec.push_back(a[i] - a[i + 1]);
}
sort(vec.begin(), vec.end());
for (int i = 0; i < k - 1; ++i) {
res += vec[i];
}
printf("%lld\n", res);
}
return 0;
}

D. Yet Another Subarray Problem

题意:

有一个序列\(a_i\),定义一个子区间的价值:

\[\begin{eqnarray*}
\sum\limits_{i = l}^r a_i - k \left\lceil \frac{r - l + 1}{m} \right\rceil
\end{eqnarray*}
\]

问所有子区间中最大的价值是多少?

思路:

维护一个前缀和\(S\),那么变换式子有:

\[\begin{eqnarray*}
S_r - S_l - k \left\lceil \frac{r - l}{m} \right\rceil
\end{eqnarray*}
\]

我们希望将\(\left\lceil \frac{r - l}{m} \right\rceil\)拆开成\(\left\lceil \frac{r}{m} \right\rceil - \left\lceil \frac{l}{m} \right\rceil\),但是这样是不行的。

注意到\(m\)很小,所以可以通过分类讨论一下将\(\left\lceil \frac{x}{m} \right\rceil\)按\(x \bmod m\)进行分类,然后讨论一下合并即可。

代码:

#include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 300010
int n, m, k;
ll a[N];
ll f[20]; int main() {
while (scanf("%d%d%d", &n, &m, &k) != EOF) {
for (int i = 1; i <= n; ++i) scanf("%lld", a + i);
ll res = 0;
for (int i = 0; i < m; ++i) f[i] = 0;
f[0] = -k;
for (int i = 1; i <= n; ++i) {
a[i] += a[i - 1];
for (int j = 0; j < m; ++j) {
if (m - i % m >= m - j) {
res = max(res, a[i] - f[j] - 1ll * k * (i / m + 1));
} else {
res = max(res, a[i] - f[j] - 1ll * k * (i / m + 2));
}
}
f[i % m] = min(f[i % m], a[i] - 1ll * k * (i / m + 1));
}
printf("%lld\n", res);
}
return 0;
}

E. Culture Code

题意:

有\(n\)个俄罗斯套娃,每个套娃有内径\(in_i\)和外径\(out_i, out_i > in_i\),一个套娃\(i\)能套在套娃\(j\)里面,当且仅当\(out_i \leq in_j\)。

定义一组套在的额外空间为

\[\begin{eqnarray*}
in_1 + (in_2 - out_1) + (in_3 - out_3) + \cdots + (in_k - out_{k - 1})
\end{eqnarray*}
\]

其中\(in_k\)为最外成那个套娃的内径。

定义一组套娃是个极大套娃组:当且仅当不能再有另外一个套娃套在他们身上了。

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

思路:

先将套娃分成两类:

  • 第一类:没有另外一个套娃能套在它头上
  • 第二类:至少存在一个套娃能够套在它头上

那么考虑把方案数全都算在第一类套娃头上。

那么先将所有套娃按内径从小到大排序,那么定义\(f[i]\)表示第\(i\)个套娃产生最小额外空间时的方案数,那么它能从第\(j\)个套娃转移过来当且仅当第\(out_j <= in_i\)。

那么再考虑变换额外空间的式子:

\[\begin{eqnarray*}
in_k + \sum\limits_{i = 1}^{k - 1} out_i - in_i
\end{eqnarray*}
\]

这样就变成了极大套娃组的额外空间中除了第一个套娃,其他套娃的贡献独立,为\(out_i - in_i\)。

那么转移的时候维护一下最小额外空间,如果最小额外空间相同就合并方案数,否则更新方案数。

代码:

#include <bits/stdc++.h>
using namespace std; #define ll long long
#define INFLL 0x3f3f3f3f3f3f3f3f
#define N 400010
#define pii pair <ll, ll>
#define fi first
#define se second
const ll p = 1e9 + 7;
int n, tot;
pii a[N];
int b[N];
ll c[N], d[N]; struct SEG {
struct node {
ll Min, sum;
node() {
sum = 0;
Min = INFLL;
}
node(ll Min, ll sum) : Min(Min), sum(sum) {}
node operator + (const node &other) const {
node res = node();
if (Min == other.Min) {
res.Min = Min;
res.sum = (sum + other.sum) % p;
} else if (Min < other.Min) {
res.Min = Min;
res.sum = sum;
} else {
res.Min = other.Min;
res.sum = other.sum;
}
return res;
}
}t[N << 2], res;
void build(int id, int l, int r) {
t[id] = node();
if (l == r) return;
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
}
void update(int id, int l, int r, int pos, node x) {
if (l == r) {
t[id] = t[id] + x;
return;
}
int mid = (l + r) >> 1;
if (pos <= mid) update(id << 1, l, mid, pos, x);
else update(id << 1 | 1, mid + 1, r, pos, x);
t[id] = t[id << 1] + t[id << 1 | 1];
}
void query(int id, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) {
res = res + t[id];
return;
}
int mid = (l + r) >> 1;
if (ql <= mid) query(id << 1, l, mid, ql, qr);
if (qr > mid) query(id << 1 | 1, mid + 1, r, ql, qr);
}
}seg; int id(int x) {
return lower_bound(b + 1, b + 1 + tot, x) - b;
} int main() {
while (scanf("%d", &n) != EOF) {
tot = 0;
for (int i = 1; i <= n; ++i) scanf("%lld%lld", &a[i].fi, &a[i].se);
for (int i = 1; i <= n; ++i) {
b[++tot] = a[i].fi;
b[++tot] = a[i].se;
}
sort(b + 1, b + 1 + tot);
tot = unique(b + 1, b + 1 + tot) - b - 1;
sort(a + 1, a + 1 + n, [](pii x, pii y) {
if (x.se != y.se) return x.se < y.se;
return x.fi > y.fi;
});
ll Min = INFLL;
ll res = 0;
seg.build(1, 1, tot);
for (int i = 1; i <= n; ++i) {
seg.res = SEG::node();
seg.query(1, 1, tot, 1, id(a[i].se));
if (seg.res.Min == INFLL) {
seg.res = SEG::node(-a[i].fi + a[i].se, 1);
seg.update(1, 1, tot, id(a[i].fi), seg.res);
c[i] = a[i].se;
d[i] = 1;
} else {
c[i] = a[i].se + seg.res.Min;
d[i] = seg.res.sum;
seg.res.Min += -a[i].fi + a[i].se;
seg.update(1, 1, tot, id(a[i].fi), seg.res);
}
if (a[i].fi > a[n].se) {
Min = min(Min, c[i]);
}
}
for (int i = 1; i <= n; ++i) {
if (a[i].fi > a[n].se && c[i] == Min) {
res = (res + d[i]) % p;
}
}
printf("%lld\n", res);
}
return 0;
}

Educational Codeforces Round 69的更多相关文章

  1. Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code

    Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code 题目链接 题意: 给出\(n\)个俄罗斯套娃,每个套娃都有一个\( ...

  2. Educational Codeforces Round 69 D. Yet Another Subarray Problem

    Educational Codeforces Round 69 (Rated for Div. 2) D. Yet Another Subarray Problem 题目链接 题意: 求\(\sum_ ...

  3. Educational Codeforces Round 69 D E

    Educational Codeforces Round 69 题解 题目编号 A B C D E F 完成情况 √ √ √ ★ ★ - D. Yet Another Subarray Problem ...

  4. Educational Codeforces Round 69 (Rated for Div. 2)

                                                                                                  A. DIY ...

  5. Educational Codeforces Round 69 (Rated for Div. 2) D. Yet Another Subarray Problem 背包dp

    D. Yet Another Subarray Problem You are given an array \(a_1, a_2, \dots , a_n\) and two integers \( ...

  6. Educational Codeforces Round 69 (Rated for Div. 2) C. Array Splitting 水题

    C. Array Splitting You are given a sorted array

  7. Educational Codeforces Round 69 (Rated for Div. 2) A~D Sloution

    A. DIY Wooden Ladder 题意:有一些不能切的木板,每个都有一个长度,要做一个梯子,求梯子的最大台阶数 做梯子的木板分为两种,两边的两条木板和中间的若干条台阶木板 台阶数为 $k$ 的 ...

  8. Educational Codeforces Round 69 E - Culture Code (最短路计数+线段树优化建图)

    题意:有n个空心物品,每个物品有外部体积outi和内部体积ini,如果ini>outj,那么j就可以套在i里面.现在我们要选出n个物品的一个子集,这个子集内的k个物品全部套在一起,且剩下的物品都 ...

  9. Educational Codeforces Round 69 (Rated for Div. 2)D(DP,思维)

    #include<bits/stdc++.h>using namespace std;int a[300007];long long sum[300007],tmp[300007],mx[ ...

随机推荐

  1. Vue.js源码全方位深入解析--学习笔记

    模板中的插入变量是如何渲染到DOM上的? initMixin(Vue)->_init->$options-> $mount()当执行该挂载方法时DOM变化 为什么可以通过this访问 ...

  2. Qt4 和 Qt5 模块的分类

    Qt5 与 Qt4 其中的一个区别是底层架构进行了改变,Qt5 引入了更加详细的模块化的概念,将众多功能细分到几个模块之中,Qt4 则是一种粗略的划分.本文主要对 Qt5 和 Qt4的模块进行一个简单 ...

  3. 多线程面试题之【三线程按顺序交替打印ABC的方法】

    建立三个线程,线程名字分别为:A.B.C,要求三个线程分别打印自己的线程名字,但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印.打印10轮,打印完毕控制台输出字符串:&q ...

  4. Luogu5307 [COCI2019] Mobitel 【数论分块】【递推】

    题目分析: 对于向上取整我们总有,$\lceil \frac{\lceil \frac{n}{a} \rceil}{b} \rceil = \lceil \frac{n}{a*b} \rceil$这个 ...

  5. Spring Cloud Alibaba学习笔记(7) - Sentinel规则持久化及生产环境使用

    Sentinel 控制台 需要具备下面几个特性: 规则管理及推送,集中管理和推送规则.sentinel-core 提供 API 和扩展接口来接收信息.开发者需要根据自己的环境,选取一个可靠的推送规则方 ...

  6. Django_rest_framework分页

    分页基本流程及配置 1.基于LimitOffsetPagination做分页,根据配置 from rest_framework.pagination import LimitOffsetPaginat ...

  7. 【转载】 C#中使用Count方法获取List集合中符合条件的个数

    很多时候操作List集合的过程中,我们需要根据特定的查询条件,获取List集合中有多少个实体对象符合查询条件,例如一批产品的对象List集合,如果这批产品的不合格数量大于10则重点备注.在C#中可以自 ...

  8. nodejs库express是如何接收inbound json请求的

    这样几行简单的代码创建一个web服务器: var express = require('express'); var app = express(); var server = require('ht ...

  9. Robo 3T SQL

    查询指定日期,指定显示字段,排序,注释功能 db.getCollection('spuBasisInfo') .find({"createTime":{$gte:ISODate(& ...

  10. JAVA笔记整理(九),JAVA中的集合

    在工作中,我们经常需要将多个对象集中存放,可以使用数组,但是数组的长度一旦固定之后是不可变的,为了保存数量确定的数据,我们可以使用JAVA中的集合. 在我看来,JAVA中的集合可以看作是一个特殊的数据 ...