Codeforces Educational Round 100(Div.2)


 

A、Dungeon

题意:

你现在要打死三个怪物,你的每次攻击可以挑一次怪物降低一点$HP$,且第$7$的倍数次出招可以$AOE$,每个怪物降低一点$HP$,问你能不能最后用$AOE$把它们同时都打死。

题解:

每$7$次攻击能造成$9$点伤害,所以总血量是$9$的倍数,且$AOE$次数(总血量除$9$的商)要大于等于最少血的怪物时,就行,否则不行。

B、Find The Array

题意:

给你一个序列$a$,构造一个相同长度的序列$b$,使得$b_i$和$b_{i+1}$其中一个能整除另一个。且$\sum \limits _{i=1}^{n} |a_i - b_i| \times 2 \leq \sum \limits _{i =1} ^{n} a_i$。

题解:

自己想的一个算法:想要每个数都达到$|a_i - b_i | \ leq a_i$,可以计算出$b_i \geq \frac{a_i}{2}$且$b_i \leq \frac{3 \times a_i }{2}$。所以就选择其中一个数固定,然后向左右两边按这个规则扩展,一旦找到答案就输出。

但是这个太麻烦了。

注意到题目所求式子,这个暗示了按奇偶分类即可。因为奇数位置和与偶数位置和一定有一个大于等于序列$a$的和的一半,我们只要让$b$中这一半和$a$中一样,其他的是$1$就行了。

C、Busy Robot

题意:

给出$n$个操作,第$i$个操作在$t_i$时刻下达,让机器人从当前位置去$x_i$,如果前面的操作没完成,这个操作忽略,定义一个操作“成功”,是说在$[t_i,t_{i+1}]$时间内的任意时刻,机器人在$x_i$。$t_{n+1} = INF$,按输入顺序操作,问成功的操作次数,保证$t_{i+1}>t_i$。

题解:

首先计算出能被执行的操作是什么,然后在这些操作中间,计算出每个时间区间机器人的位置,然后判断操作的目标位置在不在其中,如果在就统计。

坑点:有的时候机器人跑完了但是计算的时候会被视为仍在跑,计算出的区间不是实际的区间,所以需要$min$和$max$约束一下。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 1e5 + 5;
 5 pair<ll, ll> p[N];
 6 int getdir(ll s, ll t)
 7 {
 8     if (s == t)
 9         return 0;
10     else if (s > t)
11         return -1;
12     return 1;
13 }
14 bool inrange(ll l, ll r, ll pos)
15 {
16     if (l > r)
17         swap(l, r);
18     return l <= pos && pos <= r;
19 }
20 void solve()
21 {
22     int n;
23     scanf("%d", &n);
24     for (int i = 1; i <= n; ++i)
25         scanf("%lld%lld", &p[i].first, &p[i].second);
26     p[n + 1].first = 1e18;
27     ll pos = 0, ans = 0;
28     for (int i = 1; i <= n;)
29     {
30         int dir = getdir(pos, p[i].second);
31         int nxt = i + 1;
32         while (nxt <= n && p[nxt].first < abs(p[i].second - pos) + p[i].first)
33             ++nxt;
34         for (int j = i; j < nxt; ++j)
35         {
36             ll l = pos + dir * (p[j].first - p[i].first);
37             ll r = pos + dir * (p[j + 1].first - p[i].first);
38             if (dir == -1)
39                 l = max(l, p[i].second), r = max(r, p[i].second);
40             else
41                 l = min(l, p[i].second), r = min(r, p[i].second);
42             if (inrange(l, r, p[j].second))
43                 ++ans;
44         }
45         pos = p[i].second;
46         i = nxt;
47     }
48     printf("%lld\n", ans);
49 }
50 int main()
51 {
52     int t;
53     scanf("%d", &t);
54     while (t--)
55         solve();
56     return 0;
57 }
View Code

D、Pairs

题意:

把$1$到$2 \times n$个数分成$n$个$pair$,对于$x$从$0$到$n$,选出$x$个$pair$取最小值,剩下的取最大值构成给定的序列,问有几个$x$能构造出来。

题解:

可以知道这个可行$x$的选取是在一段连续区间上的,因为如果存在多段区间上,它们可以通过交换凑到一个区间上。然后考虑左右端点怎么计算出来,先考虑一定只能选最小值的情况,$n=5$时的$1 2 3 4 5$,如果是$1 2 4 5 6$,则$4 5 6$其中一个可以取最大值,所以我们发现,前面的非连续的区间之间的距离,即上例的$6-4=2$减一,就可以给后面的一个数放到上面,这样子,我们就可以计算出有哪些可以利用这个性质,使得$pair$可以以它为最大值时也合法,反过来也一样。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 4e5 + 5;
 5 int a[N];
 6 void solve()
 7 {
 8     int n;
 9     scanf("%d", &n);
10     for (int i = 1; i <= n; ++i)
11         scanf("%d", &a[i]);
12     a[n + 1] = n * 2 + 1;
13     int ans = n + 1, sum = 0;
14     for (int i = 1; i <= n; ++i)
15     {
16         sum += a[i] - a[i - 1] - 1;
17         if (sum == 0)
18             --ans;
19         else
20             --sum;
21     }
22     sum = 0;
23     for (int i = n; i; --i)
24     {
25         sum += a[i + 1] - a[i] - 1;
26         if (sum == 0)
27             --ans;
28         else
29             --sum;
30     }
31     printf("%d\n", ans);
32 }
33 int main()
34 {
35     int t;
36     scanf("%d", &t);
37     while (t--)
38         solve();
39     return 0;
40 }
View Code

后记:

不要死板觉得codeforces的D题E题一定是树状数组或者是线段树之类的东西QAQ,还是要多想多思考。

 

posted @ 2020-12-22 14:07  Aya_Uchida  阅读(102)  评论(0编辑  收藏  举报