1. 程式人生 > 實用技巧 >Codeforces Educational Round 100(Div.2)

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,還是要多想多思考。