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)View Code7 { 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 }View Code
後記:
不要死板覺得codeforces的D題E題一定是樹狀陣列或者是線段樹之類的東西QAQ,還是要多想多思考。