Решения заданий заочного тура (Интернет-тура)

XI Республиканской олимпиады имени

ИНФОРМАТИКА

8-9 классы

1. «Фигурное катание»

Необходимо считать данные в три одномерных массив, состоящий из трех строк и n столбцов, следующим образом. Номер столбца – есть номер фигуриста. В первой строке содержится сумма первых трех баллов, во второй строке – сумма баллов с 4-го по 6-й баллы, в третьей – сумма с 7-го по 9-й баллы соответствующего фигуриста. Затем найти максимальные элементы в массивах.

Если же несколько максимальных элементов, то занести номера элементов с максимальным значением в другой массив для каждого такого массива. Провести сортировку элементов получившихся массивов. И вывести значения данных в в массивах (уже отсортированном).

2. «Модные числа»

import java. io.*;

import java. util.*;

public class beauty_ft implements Runnable {

public final static int MAX_N = (int) 2e5;

private Scanner in;

private PrintWriter out;

String fname = "beauty";

private void myAssert(boolean e, String message) {

if (!e) {

throw new Error("Assertion failure!!! " + message);

}

}

public void solve() {

int n = in. nextInt();

myAssert(1 <= n && n <= "");

int x = 1;

while (true) {

int t = x;

int c = 0;

int s = 0;

while (t > 0) {

c++;

s += t % 10;

t /= 10;

}

if (s % c == 0) {

n--;

}

if (n == 0) {

out. println(x);

break;

}

x++;

}

}

public void run() {

try {

solve();

} catch (Exception e) {

e. printStackTrace();

НЕ нашли? Не то? Что вы ищете?

System. exit(1);

} finally {

out. close();

}

}

public beauty_ft() {

try {

in = new Scanner(new File(fname + ".in"));

out = new PrintWriter(new File(fname + ".out"));

} catch (Exception e) {

e. printStackTrace();

System. exit(1);

}

}

public static void main(String[] args) {

Locale. setDefault(Locale. US);

new Thread(new beauty_ft()).start();

}

}

3. «Забавные преобразования»

Задачу можно решать непосредственно путем перевода исходного числа в двоичную систему счисления, получения всех его циклических сдвигов, перевода их в десятичную систему и выбора максимального из них:

Var I, J, Maх, Мax, NumDigits, Digit :Integer;

Digits: Array[1..20] Of Integer;

Begin

<ввод исходвого числа в переменную>

Мах := Nira; KiraDigits := 0; {перевод в двоичную систему}

While Kim > 0 Do Begin Inc(NuaDigits);

Digits[KumDigits] := Кurn Mod 2;

Nira := Num Div 2

End;

For I:=l To NumDigits - 1 Do Begin {сдвиг}

Digit := Digits[1];

For J := 2 To KumDigits Do Digits[J-l] := Digits[J];

Digits[KumDigits] := Digit; {перевод в десятичную систему}

Hun := 0;

For J := KumDigits DownTo 1 Do

Kum := Kum*2 + Digits [J] ;

If Kum > Max Then Max := Kum

End;

<вывод значения переменной Max в качестве ответа>

End;

Естественно, можно было решать эту задачу с использованием опера­ции побитового сдвига SHR, не переводя число явно в двоичную систему.

4. «Точки»

Const

MaxN = 1000;

Type

Float = Extended;

TPoint = Record

x, y: Longint;

End;

Var N: Integer;

P: Array [1..MaxN] Of TPoint;

Sc: Array [1..MaxN] Of Longint;

Best: Float;

Procedure Init;

Var i: Integer;

Begin

Assign(input,'d. in'); Reset(input);

Read(N); For i := 1 To N Do With p[i] Do Read(x, y);

Close(input);

End;

Function GLine(Const p1,p2,p: TPoint): Longint;

Begin

GLine := (p. x-p1.x)*(p2.y-p1.y) - (p. y-p1.y)*(p2.x-p1.x);

End;

Function Search(a, b: Integer): Integer;

Var i: Integer;

Begin

i := 1; While (i < n) And (GLine(p[a],p[b],p[i]) = 0) Do inc(i);

Search := i;

End;

Procedure Swap(i, j: Integer);

Var c: TPoint; t: Longint;

Begin

c := p[i]; p[i] := p[j]; p[j] := c;

t := sc[i]; sc[i] := sc[j]; sc[j] := t;

End;

Procedure QSort(b, l: Integer);

Var i, j: Integer; x: Longint;

Begin

i := b; j := l; x := Sc[(i+j) shr 1];

Repeat

While (x > sc[i]) Do inc(i);

While (x < sc[j]) Do dec(j);

If i<=j Then

Begin

Swap(i, j); Inc(i); Dec(j);

End;

Until i>j;

If i < l Then QSort(i, l);

If b < j Then QSort(b, j);

End;

Function Len(a, b: Integer): Float;

Begin

Len := Sqrt(Sqr(p[a].x-p[b].x)+Sqr(p[a].y-p[b].y));

End;

Function Min(a, b: Float): Float;

Begin

If a < b Then Min := a Else Min := b;

End;

Procedure Solve;

Var r, i: Integer; t: Float;

Begin

If GLine(p[1],p[2],p[3]) = 0 Then r := Search(1,2)

Else If N > 3 Then

Begin

If GLine(p[1],p[2],p[4]) = 0 Then r := Search(1,2) Else

If GLine(p[2],p[3],p[4]) = 0 Then r := Search(2,3) Else

If GLine(p[1],p[3],p[4]) = 0 Then r := Search(1,3) Else

WriteLn('Error');

End

Else r := 3;

Swap(n, r);

For i := 1 To n-1 Do

sc[i] := (p[2].x-p[1].x)*(p[i].x-p[1].x) +

(p[2].y-p[1].y)*(p[i].y-p[1].y);

QSort(1, n-1);

Best := Len(1,n-1) + Min(Len(n,1), Len(n, n-1));

For i := 1 To N-2 Do

Begin

t := Len(1,i) + Len(i+1,n-1);

Best := Min(Best, t+Len(i, n)+Len(i+1,n));

Best := Min(Best, t+Len(i, n)+Len(n-1,n));

Best := Min(Best, t+Len(1,n)+Len(i+1,n));

Best := Min(Best, t+Len(1,n)+Len(n-1,n));

End;

End;

Procedure Done;

Begin

Assign(output, 'd. out'); Rewrite(output);

WriteLn(Best:0:15);

Close(output);

End;

BEGIN

Init; Solve; Done;

END.

5. «Размерность строки»

import java. io.*;

import java. util.*;

public class string_ft implements Runnable {

public final static int MAX_N = (int) 2e5;

private Scanner in;

private PrintWriter out;

String fname = "string";

private void myAssert(boolean e, String message) {

if (!e) {

throw new Error("Assertion failure!!! " + message);

}

}

public void solve() {

String s = in. next();

int n = s. length();

char[] c = s. toCharArray();

myAssert(1 <= n && n <= 2e5, "");

for (int i = 0; i < n; i++) {

myAssert('a' <= c[i] && c[i] <= 'z', "");

}

int max = Integer. MIN_VALUE;

int min = Integer. MAX_VALUE;

for (int i = 0; i < n; i++) {

max = Math. max(max, c[i]);

min = Math. min(min, c[i]);

}

int lastMin = -1;

int lastMax = -1;

int ansLen = Integer. MAX_VALUE;

int ansPos = -1;

for (int i = 0; i < n; i++) {

if (c[i] == max) {

if (lastMin!= -1) {

int cl = i - lastMin + 1;

if (cl < ansLen) {

ansPos = lastMin;

ansLen = cl;

}

}

lastMax = i;

}

if (c[i] == min) {

if (lastMax!= -1) {

int cl = i - lastMax + 1;

if (cl < ansLen) {

ansPos = lastMax;

ansLen = cl;

}

}

lastMin = i;

}

}

out. println(s. substring(ansPos, ansPos + ansLen));

}

public void run() {

try {

solve();

} catch (Exception e) {

e. printStackTrace();

System. exit(1);

} finally {

out. close();

}

}

public string_ft() {

try {

in = new Scanner(new File(fname + ".in"));

out = new PrintWriter(new File(fname + ".out"));

} catch (Exception e) {

e. printStackTrace();

System. exit(1);

}

}

public static void main(String[] args) {

Locale. setDefault(Locale. US);

new Thread(new string_ft()).start();

}

}

6. «Несовпадения»

Необходимо сформировать двумерный массив a[n, m] из элементов – соответствующих цифр на карточках.

Для подсчета «несовпадений» необходимо иметь счетчик s, который увеличивать на единицу при выполнении следующего условия: a[i, j]+a[i+1,j]+a[i, j+1]+a[i+1,j+1]=18.

9. «Слова»

Заметим, что нам не важно, где именно находятся буквы, которые вы­черкивает Мегамозг. Поэтому не обязательно искать именно те буквы, которые составляют слова: мы можем вычеркивать такие же буквы из любой клетки таблицы. После этого наблюдения решение задачи уже становится делом техники. Приведем два способа решения задачи.

Первый способ.

Воспользуемся стандартными функциями для работы со строками, чтобы сделать код лаконичным. Сначала мы запишем все символы из таблицы в одну строку (их не более 100. поэтому в Паскале можно воспользоваться стандартным типом string):

S:=";

for I:=l to H do begin

ReadLn(V);

S:=S+V;

end;

Теперь будем читать слова по одному и удалять каждую букву каждого слова из строки S:

for J:=l to М do begin

ReadLn(V);

for I:=l to Length(V) do Delete (S, Роs(V[i], S), 1);

end;

Напомним, что функция Pos возвращает позицию первого вхождения символа в строку, а процедура Delete удаляет из данной строки символ (в общем случае — подстроку) в данной позиции. После выполнения этого фрагмента программы в строке S останутся ровно те символы, которые нам требуется вывести:

write (s);

Второй способ.

Заведем массив:

a: array ['A'..'Z'] of integer;

Подсчитаем, сколько раз встречается каждая буква латинского алфа­вита в исходном квадрате:

for i:=l to n do begin for j:=l to n do begin

read (с);

inc(a.[c]) end; readln; end;

Теперь будем считывать слова и «вычеркивать» встречающиеся в них буквы, уменьшая соответствующие счетчики:

for i:=l to m do begin readln (s);

for j:=l to length(s) do dec(a.[s[j]])

end;

Теперь напечатаем оставшиеся буквы:

for с: = 'А' to 'Z' do for i:=l to a.[c] do write (c);

10. «Змеи Горынычи»

Помимо двух - и трёхголовых драконов, введём новую породу – одноголовых (такие драконы получаются, если отрубить одну голову у двухголового или две головы у трёхголового).

Пусть в данный момент у нас имеется A – одноголовых драконов, B – двухголовых и C – трёхголовых.

Отметим, что каждая тройка чисел (A, B,C) однозначно задаёт: выиграем мы, стартуя из этой позиции, или проиграем.

Если все три числа равны 0, то в этой позиции мы проиграли (противник уже успел перерубить оставшихся драконов).

Иначе есть несколько возможных вариантов развития событий:

Если A > 0

можно перейти в (A-1,B, C) //Отрубаем 1 голову у одноголового

Если B > 0

можно перейти в (A+1,B-1,C) //Отрубаем 1 голову у двухглавого

можно перейти в (A, B-1,C) //Отрубаем 2 головы у двухглавого

Если С > 0

можно перейти в (A, B+1,C-1) //Отрубаем 1 голову у трёхглавого

можно перейти в (A+1,B, C-1) //Отрубаем 2 головы у трёхглавого

можно перейти в (A, B,C-1) //Отрубаем 3 головы у трёхглавого

Если хотя бы в одном из рассмотренных случаев нам удастся перейти в проигрышное положение, то это значит, что текущая позиция выигрышная для «М…мозга» (он сможет перевести противника в заведомо проигрышное положение), в противном случае – он сам проиграл.

Создадим трёхмерный массив W размерами [N+M+1][N+1][M+1], описывающий состояние для данного количества драконов, где в ячейке W[i][j][k] хранится

1, если начиная из такой позиции «М…мозг» выигрывает

-1, если проигрывает

0, если результат для данной ячейки ещё не определён.

(Из-за маленького объёма предоставляемой памяти размер ячейки массива не должен превышать 1 байта).

Как мы уже отметили W[0][0][0] = -1.

Так как суммарное количество голов у драконов конечно, и после каждого удара «М…мозга» оно уменьшается, то рано или поздно кто-то из «М…мозгов» окажется в этой позиции. Следовательно, запустив рекурсивно функцию заполнения массива по описанному выше алгоритму, мы сможем определить выигрышность или проигрышность исходной позиции W[0][N][M].

Таким образом, если после заполнения массива W[0][N][M] равно 1, то выигрывает первый «М…мозг», иначе – второй.

Чтобы вывести удовлетворяющие начальные ходы надо ещё раз просмотреть содержимое ячеек, описывающих события, возможно, следующие за исходным и вывести описание ударов, переводящих противника в проигрышное положение.

Сложность программы: так как, узнав значение для ячейки W[i][j][k] мы больше его не пересчитываем и 0 <= i <= N+M, 0 <= j <= N, 0 <= k <= M, то всего придётся обрабатывать не более (N+M)*N*M следовательно данная программа требует O((N+M)*N*M) времени и

O((N+M)*N*M) памяти.

//Если всего драконов четное количество, то выигрывает второй, а если нечетное – первый. Просто сложите два числа и проверьте на четность.