# Разбор задач 2013 года Если Вы не знали как решать какую-то задачу и Вам было лень разбираться в коде на Pascal, то это пост специально для Вас. :::warning Убедительная просьба не копировать коды и не пересылать их. Помните -- Вы решаете задачи для себя! ::: ## [1. Считалки](https://codeforces.com/group/skz9fIV5Hq/contest/261187/problem/2013_1) :::spoiler Разбор :::info Самым коротким решением в этой задаче является моделирование считалок. Теперь нам нужна структура данных, которая может удалять $k$-ю порядковую статистику. Для этого идеально подойдет *ordered_set*. Давайте хранить в *ordered_set* номера всех детей. На очередном ходу будем высчитывать номер игрока, который выйдет из круга. Удалим его из *ordered_set*. Такую несложную операцию повторим $N - 1$ раз. Асоптотика: $O(N * log(N))$. ::: :::spoiler Авторское решение (Pascal) ```pascal program solution; var left, right, parent : array[1..25000] of longint; part : array[1..25000] of longint; v, node_number : array[0..25000] of longint; root : longint; n, i, j : longint; cur : longint; sum : int64; function init_tree(l,r,p : longint):longint; var t : longint; begin if l>r then init_tree:=0 else begin t := (l+r) div 2; left[t] := init_tree(l, t-1, t); right[t] := init_tree(t+1, r, t); parent[t]:= p; node_number[t] := 1; if left[t]<>0 then node_number[t] := node_number[t] + node_number[left[t]]; if right[t]<>0 then node_number[t] := node_number[t] + node_number[right[t]]; init_tree:=t end end; { init_tree } procedure forget_node(x, y : longint); begin if parent[x] = 0 then root := y else if left[parent[x]] = x then left[parent[x]] := y else right[parent[x]] := y; if y<>0 then parent[y] := parent[x] end; { forget_node } procedure delete_node(x : longint); var y,z : longint; begin if left[x]=0 then forget_node(x, right[x]) else if right[x] = 0 then forget_node(x, left[x]) else begin y := right[x]; while left[y] <> 0 do y := left[y]; z:=part[y]; part[y]:=part[x]; part[x]:=z; forget_node(y, right[y]); x:=y; end; x:=parent[x]; while x<>0 do begin node_number[x] := node_number[x] - 1; x := parent[x]; end end; { delete_node } function index(i : longint):longint; var t : longint; begin t:=root; while i <> node_number[left[t]]+1 do if i <= node_number[left[t]] then t:=left[t] else begin i:=i-1-node_number[left[t]]; t:=right[t] end; index := t; end; { index } begin read(n); sum:=0; for i:=1 to n do begin read(v[i]); part[i]:=i; sum:=sum+v[i]; end; node_number[0]:=0; root:=init_tree(1,n,0); cur := 0; for i := n downto 2 do begin cur := (sum + cur) mod i; if cur = 0 then j := index(i) else begin j:=index(cur); cur := cur - 1 end; sum := sum - v[part[j]]; delete_node(j) end; writeln(part[root]); end. ``` ::: :::spoiler Код (C++, автор: [Zhdun](https://codeforces.com/profile/Zhdun)) ```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> 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>; int main() { int n; cin >> n; ordered_set<int> all; ll sum = 0; int a[n + 1]; for (int i = 1; i <= n; ++i) { int x; cin >> x; all.insert(i); sum += x; a[i] = x; } int nach = 1; int del; int kol; int pos; while(n > 1) { pos = (sum + nach - 1) % n; if (!pos) pos = n; int x = *all.find_by_order(pos - 1); sum -= a[x]; all.erase(x); nach = pos; if (n - 1 < nach) nach = 1; n--; } cout << *all.find_by_order(0) << endl; return 0; } ``` ::: ## [2. Тренировка (упрощённая версия)](https://codeforces.com/group/skz9fIV5Hq/contest/261187/problem/2013_2) :::spoiler Разбор :::info Считаем динамику $dp_i$ -- количество способов дойти в точку $i$. Переход: $dp_i = \begin{cases} dp_{i - 2} + dp_{i - 3} \text{, если } i-3 \geq 0 \\ dp_{i - 2} \text{, если } i - 3 < 0 \end{cases}$ Асимптотика: $O(N)$. ::: :::spoiler Авторское решение (Pascal) ```pascal program solution; var n,i : integer; f : array[1..160] of qword; begin readln(n); f[1]:=1; f[2]:=0; f[3]:=1; for i:=4 to n do f[i]:=f[i-2] + f[i-3]; writeln(f[n]); end. ``` ::: :::spoiler Код (C++, автор: [Adamenko](https://codeforces.com/profile/Adamenko)) ```cpp #include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; vector<unsigned long long> dp(n, 0); dp[0] = 1; dp[1] = 0; for (int i = 2; i < n; ++i) dp[i] = dp[i - 2] + (i - 3 >= 0 ? dp[i - 3] : 0); cout << dp[n - 1] << endl; return 0; } ``` ::: ## [3. Две строки](https://codeforces.com/group/skz9fIV5Hq/contest/261187/problem/2013_3) :::spoiler Разбор :::info Давайте переберем начало подстроки в первой строке и будем жадно набирать подпоследовательность во второй строке. Асиптотика: $O(N^2)$. ::: :::spoiler Авторское решение (Pascal) ```pascal program solution; var s1, s2 : ansistring; i, j, k : integer; m, s, f : integer; begin readln(s1); readln(s2); m:=0; s:=1; f:=0; for i:=1 to length(s1) do begin j:=i; k:=1; while (j<=length(s1)) and (k<=length(s2)) do begin if (k<=length(s2)) and (s1[j]=s2[k]) then j:=j+1; k:=k+1; end; j:=j-1; if m<j-i+1 then begin m:=j-i+1; s:=i; f:=j; end; end; writeln(copy(s1,s,f-s+1)); end. ``` ::: :::spoiler Код (C++, автор: [Adamenko](https://codeforces.com/profile/Adamenko)) ```cpp #include <bits/stdc++.h> using namespace std; int main() { string s, t; cin >> s >> t; int n = int(s.size()); int m = int(t.size()); int st_ = -1; int fn_ = -1; int ma = 0; for (int z = 0; z < n; ++z) { int i = z; int j = 0; while (i < n && j < m) { if (j < m && s[i] == t[j]) i++; j++; } --i; if (ma < i - z + 1) ma = i - z + 1, st_ = z, fn_ = i; } if (st_ == -1) return 0; for (int i = st_; i <= fn_; ++i) cout << s[i]; return 0; } ``` :::