# Разбор задач 2021 года
:::warning
Убедительная просьба не копировать коды и не пересылать их. Помните -- Вы решаете задачи для себя!
:::
## 1. Простые соседних интервалов
:::spoiler Разбор
:::info
Давайте забинарим ответ. И теперь для каждого отрезка длины mid проверим, содержит ли он как минимум $K$ простых чисел. Это можно делать эффективно предпрощитав зарание массив преффиксов $pref_i$ - количество простых чисел на отрезке $[1..i]$ и при проверке в бинарном поиске за $О(n)$ проверим на корректность каждый отрезок.
:::
:::spoiler Код (C++, автор: [Adamenko](https://codeforces.com/profile/Adamenko))
```cpp
#include <bits/stdc++.h>
#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
#define pb push_back
#define F first
#define S second
#define ll long long
#define ull unsigned long long
#define ld long double
#define endl '\n'
#define TIME 1.0*clock()/CLOCKS_PER_SEC
#define pii pair < int , int >
#define Endl '\n'
#pragma GCC optimize("Ofast")
using namespace std;
using namespace __gnu_pbds;
template <typename T>
using ordered_set = tree <T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
mt19937 gen(chrono::system_clock::now().time_since_epoch().count());
const int mod = 1e9 + 7;
const int SX[4] = {0 , 1 , -1 , 0};
const int SY[4] = {1 , 0 , 0 , -1};
const int rx[8] = {1, -1, 0, 0, 1, 1, -1, -1};
const int ry[8] = {0, 0, 1, -1, 1, -1, 1, -1};
const int kx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
const int ky[8] = {2, -2, 2, -2, 1, -1, 1, -1};
typedef cc_hash_table< int, int, hash<int>, equal_to<int>, direct_mask_range_hashing<int>, hash_standard_resize_policy<hash_exponential_size_policy<>, hash_load_check_resize_trigger<true>, true>> ht;
int32_t main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#else
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int a, b, k;
cin >> a >> b >> k;
int ans = 1e9;
vector < int > pref(b + 1);
pref[0] = 0;
pref[1] = 0;
for (int i = 2;i <= b; ++i){
bool ok = 1;
for (int d = 2;d * d <= i; ++d){
if (i % d == 0){
ok = 0;
break;
}
}
pref[i] = pref[i - 1] + ok;
}
int ot = -1;
int l = 1, r = b - a + 1;
while(l <= r){
int mid = (l + r) >> 1;
bool ok = 1;
for (int i = a;i + mid - 1 <= b; ++i){
if (pref[i + mid - 1] - pref[i - 1] >= k)continue;
ok = 0;
break;
}
if (ok)r = mid - 1, ot = mid;
else l = mid + 1;
}
cout << ot << endl;
return 0;
}
```
:::
## [2. Минимумы в перестановке](https://codeforces.com/group/skz9fIV5Hq/contest/321564/problem/B)
:::spoiler Разбор
:::info
Давайте решим данную задачу для $N \leq 7$ и сделаем некоторые замечания:
1. Количество последовательностей, котоорые нам подходят под условия задачи $(N - 1) ^ 2$.
2. Три числа $N$, $N - 1$, $N - 2$ постоянно находятся "рядом" друг с другом.
Вот 4 случая расположения этих 3-х чисел:
```cpp
// 1
all[0][0] = n - 2;
all[0][1] = n - 1;
all[0][2] = n;
// 2
all[1][0] = n - 2;
all[1][1] = n;
all[1][2] = n - 1;
// 3
all[2][0] = n - 1;
all[2][1] = n;
all[2][2] = n - 2;
// 4
all[3][0] = n;
all[3][1] = n - 1;
all[3][2] = n - 2;
```
Доказательстов, почему это так происходит, оставим как домашнее задание.
3. Эти три числа двигаются от конца к началу.
1 2 3 [4 5 6]
1 2 3 [4 6 5]
1 2 3 [5 6 4]
1 2 3 [6 5 4]
1 2 [4 5 6] 3
1 2 [4 6 5] 3
1 2 [5 6 4] 3
1 2 [6 5 4] 3
...
1 [4 5 6] 3 2
1 [4 6 5] 3 2
1 [5 6 4] 3 2
1 [6 5 4] 3 2
4. Давайте рассмотрим больший пример и придумаем конструктор.
5. Давайте научимся определять последний элемент.
6. Заведем множество чисел, в которое будут входить числа от [1 до N - 3].
7. Давайте заметим, что количество последовательностей, которые заканчиваются на
$N - 3$ - 4 шт.
$N - 4$ - 8 шт.
$N - 5$ - 16 шт.
8. Давате вычтем из K -= $2^x$, где $x$ - максимальная степень двойки, которая строго меньше K. Текущий элемент последовательности это (x - 2)-ый элемент по убыванию, из множества чисел. Поставили число, затем удалили его из множества.
9. Крайний случай, когда K <= 4. Разберем его отдельно.
:::
:::spoiler Код (C++, автор: [Adamenko](https://codeforces.com/profile/Adamenko))
```cpp
#include <bits/stdc++.h>
#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
#define pb push_back
#define F first
#define S second
#define ll long long
#define ull unsigned long long
#define ld long double
#define endl '\n'
#define TIME 1.0*clock()/CLOCKS_PER_SEC
#define pii pair < int , int >
#define Endl '\n'
#pragma GCC optimize("Ofast")
using namespace std;
using namespace __gnu_pbds;
template <typename T>
using ordered_set = tree <T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
mt19937 gen(chrono::system_clock::now().time_since_epoch().count());
const int mod = 1e9 + 7;
const int SX[4] = {0 , 1 , -1 , 0};
const int SY[4] = {1 , 0 , 0 , -1};
const int rx[8] = {1, -1, 0, 0, 1, 1, -1, -1};
const int ry[8] = {0, 0, 1, -1, 1, -1, 1, -1};
const int kx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
const int ky[8] = {2, -2, 2, -2, 1, -1, 1, -1};
typedef cc_hash_table< int, int, hash<int>, equal_to<int>, direct_mask_range_hashing<int>, hash_standard_resize_policy<hash_exponential_size_policy<>, hash_load_check_resize_trigger<true>, true>> ht;
void solve(){
ll n, k;
cin >> n >> k;
if (n == 1){
cout << 1 << endl;
return;
}
if (n == 2){
if (k == 1)cout << "1 2" << endl;
else cout << "2 1" << endl;
return;
}
int all[4][3];
// 1
all[0][0] = n - 2;
all[0][1] = n - 1;
all[0][2] = n;
// 2
all[1][0] = n - 2;
all[1][1] = n;
all[1][2] = n - 1;
// 3
all[2][0] = n - 1;
all[2][1] = n;
all[2][2] = n - 2;
// 4
all[3][0] = n;
all[3][1] = n - 1;
all[3][2] = n - 2;
int ans[n];
set < int > st;
for (int i = 0;i < n; ++i)st.insert(i + 1);
st.erase(n);
st.erase(n - 1);
st.erase(n - 2);
int pos = n - 1;
while(k){
if (k <= 4){
int mem = 0;
for (int i = 0;i <= pos; ++i){
if (st.size()){
ans[i] = *st.begin();
st.erase(ans[i]);
}else{
ans[i] = all[k - 1][mem];
mem++;
}
}
k = 0;
continue;
}
ll kol = 4;
int p = 0;
while(k - kol * 2 > 0)kol *= 2, p++;
k -= kol;
vector < int > lol;
for (auto to : st)lol.pb(to);
for (int i = 0;i < p; ++i)lol.pop_back();
ans[pos] = lol.back();
st.erase(lol.back());
pos--;
}
for (auto to : ans)cout << to << " ";
cout << endl;
}
int32_t main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#else
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int t;
cin >> t;
while(t --> 0)solve();
return 0;
}
```
:::
## [3. Самый длинный слог](https://codeforces.com/group/skz9fIV5Hq/contest/261187/problem/2016_3)
:::spoiler Разбор
:::info
Это очень запарная и неприятная реализация. Разбираем все случаи (они описаны в условии). Выводим ответ.
Асимптотика: $O(N + |allS|)$, где $|allS|$ -- длина всех строк.
:::
:::spoiler Код (C++, автор: [Zhdun](https://codeforces.com/profile/Zhdun))
```cpp
#include <bits/stdc++.h>
using namespace std;
vector<string> w;
int main() {
string s;
getline(cin,s);
string cur = "";
for (int i = 0; i < s.size(); i++)
if (s[i] == ' ') {
w.push_back(cur);
cur = "";
} else cur += s[i];
if (cur != "")
w.push_back(cur);
int ma=0;
string ans;
for (int i = 0; i < w.size(); i++) {
vector<int> gl;
int pr = -1;
for (int j = 0; j < w[i].size(); j++)
if (w[i][j]=='a' || w[i][j]=='e' || w[i][j]=='y' || w[i][j]=='i' || w[i][j]=='o' || w[i][j]=='u')
gl.pb(j);
int cur = 0;
string t;
for (int j = 0; j < w[i].size(); j++)
if (cur == 0 && j < gl[0])
t += w[i][j];
else if(cur == gl.size()-1 && j >= gl[cur])
t+=w[i][j];
else if (gl[cur] == j && cur != gl.size()-1) {
t += w[i][j];
cur++;
if (gl[cur] - gl[cur-1] <= 2 || w[i][j] == 'y') {
if (t.size() > ma) {
ans = t;
ma = t.size();
}
t = "";
}
} else if (gl[cur-1] == j-1) {
t += w[i][j];
if (t.size()>1) {
if (t.size() > ma) {
ans = t;
ma = t.size();
}
t = "";
}
} else t+=w[i][j];
if(t != "") {
if (t.size() > ma) {
ans = t;
ma = t.size();
}
t = "";
}
}
cout << ans << endl;
}
```
:::
## [4. Пессимистичный прогноз](https://codeforces.com/group/skz9fIV5Hq/contest/261187/problem/2016_4)
:::spoiler Разбор
:::info
Давайте напишем жадный алгоритм. Вначале отсортируем все команды по рейтингу (он описан в условии). Теперь все команды, которые выше $k$-й, мы трогать не будем (выдавать медали). Оставшимся командам будем жадно выдавать медали по следующему алгоритму:
1. Пытаемся выдать на $1$ бронзовую медаль больше, чем у $k$-й (если можем), при этом уравниваем количество золотых и серебрянных медалей.
2. Пытаемся выдать на $1$ серебрянную медаль больше, чем у $k$-й (если можем), при этом уравниваем количество золотых медалей.
3. Пытаемся выдать на $1$ золотую медаль больше чем у $k$-й (если можем).
Асимптотика решения: $O(N * log(N))$.
:::
:::spoiler Код (C++, автор: [Adamenko](https://codeforces.com/profile/Adamenko))
```cpp
#include <bits/stdc++.h>
using namespace std;
struct node {
int Gold, Silver, Bronze;
int id;
node() {
Gold = 0;
Silver = 0;
Bronze = 0;
id = -1;
}
bool operator < (const node &x) {
if (x.Gold != Gold) return x.Gold > Gold;
else if (x.Silver != Silver) return x.Silver > Silver;
else return x.Bronze > Bronze;
}
};
vector<node> all;
int kol_Gold = 0;
int kol_Silver = 0;
int kol_Bronze = 0;
int main() {
int n, k;
cin >> n >> k >> kol_Gold >> kol_Silver >> kol_Bronze;
all.resize(n);
for (int i = 0; i < n; ++i) {
cin >> all[i].Gold >> all[i].Silver >> all[i].Bronze;
all[i].id = i + 1;
}
sort(all.rbegin(), all.rend());
int ans = 0;
bool ok = 1;
node Team;
for (int i = 0; i < n; ++i) {
if (all[i].id != k && ok) {
ans++;
continue;
}
if (all[i].id == k) {
ok = 0;
Team = all[i];
continue;
}
int need_Gold = -all[i].Gold + Team.Gold;
int need_Silver = -all[i].Silver + Team.Silver;
int need_Bronze = -all[i].Bronze + Team.Bronze;
if (need_Gold <= kol_Gold && need_Silver <= kol_Silver && need_Bronze + 1 <= kol_Bronze) {
kol_Gold -= (need_Gold < 0 ? 0 : need_Gold);
kol_Silver -= (need_Silver < 0 ? 0 : need_Silver);
kol_Bronze -= (need_Bronze >= 0 ? need_Bronze + 1 : 0);
ans++;
continue;
}
if (need_Gold <= kol_Gold && need_Silver + 1 < kol_Silver) {
kol_Gold -= (need_Gold < 0 ? 0 : need_Gold);
kol_Silver -= (need_Silver >= 0 ? need_Silver + 1 : 0);
ans++;
continue;
}
if (need_Gold + 1 <= kol_Gold) {
kol_Gold -= (need_Gold >= 0 ? need_Gold + 1 : 0);
ans++;
continue;
}
}
cout << ans << endl;
return 0;
}
```
:::