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 }
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 }
后记:
不要死板觉得codeforces的D题E题一定是树状数组或者是线段树之类的东西QAQ,还是要多想多思考。