feat(math-ct): ЦТ 2020 V1 — 32 задания (5 с PNG-изображениями) + инфраструктура PDF→PNG

This commit is contained in:
Maxim Dolgolyov
2026-06-02 09:44:23 +03:00
parent f2b0db4d9a
commit 44e262b025
9 changed files with 342 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
"""
Crop a question row from a rendered PDF page PNG.
Usage:
python crop_question_row.py <page_png> <x0> <y0> <x1> <y1> <out_png>
Coordinates are NORMALIZED (0.0-1.0) relative to page dimensions.
Add --padding 0.01 for extra border (default 0.005).
Example:
python crop_question_row.py page_005.png 0.0 0.12 1.0 0.22 2019_v1_a7.png
"""
import sys
import argparse
from PIL import Image
def crop(page_png, x0, y0, x1, y1, out_png, padding=0.005):
img = Image.open(page_png)
w, h = img.size
px0 = max(0, int((x0 - padding) * w))
py0 = max(0, int((y0 - padding) * h))
px1 = min(w, int((x1 + padding) * w))
py1 = min(h, int((y1 + padding) * h))
cropped = img.crop((px0, py0, px1, py1))
cropped.save(out_png)
print(f'Saved {out_png} ({cropped.width}x{cropped.height})')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('page_png')
parser.add_argument('x0', type=float)
parser.add_argument('y0', type=float)
parser.add_argument('x1', type=float)
parser.add_argument('y1', type=float)
parser.add_argument('out_png')
parser.add_argument('--padding', type=float, default=0.005)
args = parser.parse_args()
crop(args.page_png, args.x0, args.y0, args.x1, args.y1, args.out_png, args.padding)
+77
View File
@@ -0,0 +1,77 @@
"""
Detect horizontal table borders in a scanned PDF page PNG
and extract row bounding boxes.
Usage:
python detect_table_rows.py <page_png> [--min-width 0.7] [--debug]
Prints detected row y-ranges as normalized (0-1) coordinates.
"""
import sys
import argparse
import numpy as np
from PIL import Image
def detect_rows(page_png, min_width_frac=0.7, debug=False):
img = Image.open(page_png).convert('L') # grayscale
arr = np.array(img)
h, w = arr.shape
# Binarize: dark pixels (potential lines) = True
dark = arr < 128
# Count dark pixels per row
row_dark_count = dark.sum(axis=1)
min_dark = int(min_width_frac * w)
# Find rows that are mostly dark (horizontal lines)
is_line = row_dark_count > min_dark
# Group consecutive line pixels into bands
line_bands = []
in_band = False
band_start = 0
for y in range(h):
if is_line[y] and not in_band:
in_band = True
band_start = y
elif not is_line[y] and in_band:
in_band = False
band_end = y
line_bands.append((band_start, band_end))
if in_band:
line_bands.append((band_start, h))
if not line_bands:
print("No table lines detected. Try reducing --min-width.", file=sys.stderr)
return []
# Extract row y-ranges between consecutive line bands
rows = []
for i in range(len(line_bands) - 1):
y_top = line_bands[i][1] # bottom of upper border
y_bot = line_bands[i + 1][0] # top of lower border
if y_bot - y_top > 5: # skip tiny gaps
rows.append((y_top / h, y_bot / h))
if debug:
print(f"Detected {len(line_bands)} line bands:")
for b in line_bands:
print(f" pixels {b[0]}-{b[1]} (y={b[0]/h:.3f}-{b[1]/h:.3f})")
print(f"\nDetected {len(rows)} content rows:")
for i, (y0, y1) in enumerate(rows):
print(f" row {i}: y={y0:.3f}-{y1:.3f} (pixels {int(y0*h)}-{int(y1*h)}, height={int((y1-y0)*h)}px)")
return rows
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('page_png')
parser.add_argument('--min-width', type=float, default=0.7)
parser.add_argument('--debug', action='store_true')
args = parser.parse_args()
rows = detect_rows(args.page_png, min_width_frac=args.min_width, debug=args.debug)
if not args.debug:
for i, (y0, y1) in enumerate(rows):
print(f"row {i}: {y0:.4f} - {y1:.4f}")
+43
View File
@@ -0,0 +1,43 @@
"""
Render one or more pages of a PDF to PNG files.
Usage:
python render_pdf_page.py <pdf_path> <page_numbers> [--dpi 300] [--out-dir ./pages]
python render_pdf_page.py "F:/ЦТ/2018.pdf" "5,6,7,8" --dpi 300 --out-dir ./tmp_pages
page_numbers: comma-separated 1-based page numbers
"""
import sys
import os
import argparse
import fitz # PyMuPDF
def render_pages(pdf_path, pages, dpi=300, out_dir='.'):
os.makedirs(out_dir, exist_ok=True)
doc = fitz.open(pdf_path)
scale = dpi / 72.0
mat = fitz.Matrix(scale, scale)
results = []
for page_num in pages:
idx = page_num - 1
if idx < 0 or idx >= len(doc):
print(f' Page {page_num} out of range (doc has {len(doc)} pages)', file=sys.stderr)
continue
page = doc[idx]
pix = page.get_pixmap(matrix=mat)
out_path = os.path.join(out_dir, f'page_{page_num:03d}.png')
pix.save(out_path)
results.append(out_path)
print(f' Rendered page {page_num} -> {out_path} ({pix.width}x{pix.height})')
doc.close()
return results
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('pdf_path')
parser.add_argument('pages', help='comma-separated 1-based page numbers, e.g. "5,6,7,8"')
parser.add_argument('--dpi', type=int, default=300)
parser.add_argument('--out-dir', default='./tmp_pages')
args = parser.parse_args()
pages = [int(p.strip()) for p in args.pages.split(',')]
render_pages(args.pdf_path, pages, dpi=args.dpi, out_dir=args.out_dir)
+184
View File
@@ -0,0 +1,184 @@
'use strict';
/**
* ЦТ 2020 Математика — Вариант 1 (32 задания: A1-A20 + B1-B12)
* Ответы: страница 44-45 сборника (ЦТ 2020.pdf)
*/
const db = require('../src/db/db');
const MATH_ID = 3;
const T = {arithmetic:16,word:17,numbers:18,trig:19,quadratic:20,progression:21,inequalities:22,geometry:23,functions:24,log:25,expineq:26,equations:27,stats:28};
function getTopic(n){const e=db.prepare('SELECT id FROM topics WHERE subject_id=? AND LOWER(name)=LOWER(?)').get(MATH_ID,n);if(e)return e.id;return Number(db.prepare('INSERT INTO topics (subject_id,name) VALUES (?,?)').run(MATH_ID,n).lastInsertRowid);}
const Tx={stereo:getTopic('Стереометрия'),circle:getTopic('Окружность и круг'),sets:getTopic('Числовые промежутки'),};
const ex=new Set(db.prepare('SELECT text FROM questions WHERE subject_id=3').all().map(q=>q.text.slice(0,80).trim()));
let added=0,skipped=0;
const insQ=db.prepare(`INSERT INTO questions (subject_id,topic_id,text,type,difficulty,year,explanation,correct_text,image,source_type) VALUES (?,?,?,?,?,?,?,?,?,?)`);
const insO=db.prepare(`INSERT INTO options (question_id,text,is_correct,order_index) VALUES (?,?,?,?)`);
function q(tid,text,opts,diff,year,img){
const key=text.slice(0,80).trim();if(ex.has(key)){skipped++;return;}ex.add(key);
const r=insQ.run(MATH_ID,tid,text,'single',diff,year||null,null,null,img||null,'ЦТ');
const id=r.lastInsertRowid;opts.forEach((o,i)=>insO.run(id,o.t,o.c?1:0,i));added++;
}
function fb(tid,text,ans,diff,year){
const a=String(ans);
const key=text.slice(0,80).trim();if(ex.has(key)){skipped++;return;}ex.add(key);
insQ.run(MATH_ID,tid,text,'fill-blank',diff,year||null,null,a,null,'ЦТ');
added++;
}
const run=db.transaction(()=>{
// ══ ЧАСТЬ A ══════════════════════════════════════════════════
// A1 — точка на графике y=5^x (ответ: 4 — точка (2;25))
q(T.functions,`Укажите номер точки, которая принадлежит графику функции \\(y=5^x\\):\n1) \\((25;\\,2)\\); 2) \\((2;\\,10)\\); 3) \\((5;\\,25)\\); 4) \\((2;\\,25)\\); 5) \\((1;\\,0)\\).`,
[{t:'4',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'5',c:false}],
1,2020);
// A2 — вписанный угол KML=38°, найти KNL [РИСУНОК; ответ: 4 — 52°]
q(Tx.circle,`A2. Если вписанный угол \\(KML\\), изображённый на рисунке, равен 38°, то вписанный угол \\(KNL\\) равен:\n1) 46°; 2) 38°; 3) 19°; 4) 52°; 5) 76°.`,
[{t:'4',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'5',c:false}],
1,2020,'/img/ct/math/2020_v1_a2.png');
// A3 — выражение для числа с c десятками и 3 единицами (ответ: 4 — 10c+3)
q(T.numbers,`Укажите номер выражения для определения натурального числа, содержащего \\(c\\) десятков и 3 единицы:\n1) \\(c+3\\); 2) \\(3c\\); 3) \\(3c+10\\); 4) \\(10c+3\\); 5) \\(30+c\\).`,
[{t:'4',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'5',c:false}],
1,2020);
// A4 — наименьшее слагаемое меньше суммы на сколько, x+20=80 (ответ: 2 — 60)
q(T.numbers,`Определите, на сколько наименьшее слагаемое меньше суммы, если известно, что \\(x+20=80\\):\n1) 80; 2) 60; 3) 20; 4) 40; 5) 100.`,
[{t:'2',c:true},{t:'1',c:false},{t:'3',c:false},{t:'4',c:false},{t:'5',c:false}],
1,2020);
// A5 — точка, симметричная A(5) относительно B(19) (ответ: 1 — C(33))
q(T.numbers,`Среди точек \\(C(33)\\), \\(D(24)\\), \\(E(28)\\), \\(F(43)\\), \\(K(12)\\) координатной прямой укажите точку, симметричную точке \\(A(5)\\) относительно точки \\(B(19)\\):\n1) \\(C(33)\\); 2) \\(D(24)\\); 3) \\(E(28)\\); 4) \\(F(43)\\); 5) \\(K(12)\\).`,
[{t:'1',c:true},{t:'2',c:false},{t:'3',c:false},{t:'4',c:false},{t:'5',c:false}],
1,2020);
// A6 — значение (3 1/7 - 2)·(1+3/4):9 (ответ: 5 — 2/9)
q(T.numbers,`Найдите значение выражения \\(\\left(3\\dfrac{1}{7}-2\\right)\\cdot\\left(1+\\dfrac{3}{4}\\right)\\div9\\):\n1) \\(1\\dfrac{41}{63}\\); 2) \\(\\dfrac{3}{28}\\); 3) \\(1\\dfrac{19}{252}\\); 4) \\(-\\dfrac{11}{36}\\); 5) \\(\\dfrac{2}{9}\\).`,
[{t:'5',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'4',c:false}],
1,2020);
// A7 — угол ANM четырёхугольника ABMN [РИСУНОК; ответ: 4 — 133°]
q(T.geometry,`A7. На рисунке изображён треугольник \\(ABC\\), в котором \\(\\angle ABC=104°\\), \\(\\angle ACB=29°\\). Используя данные рисунка, найдите градусную меру угла \\(ANM\\) четырёхугольника \\(ABMN\\):\n1) 151°; 2) 128°; 3) 119°; 4) 133°; 5) 104°.`,
[{t:'4',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'5',c:false}],
2,2020,'/img/ct/math/2020_v1_a7.png');
// A8 — число марок в альбоме, кратное 3 (ответ: 5 — 39)
q(T.word,`У Юры есть некоторое количество марок, а у Яна марок в 2 раза больше, чем у Юры. Мальчики поместили все свои марки в один альбом. Среди чисел 26; 38; 20; 37; 39 выберите то, которое может выражать количество марок, оказавшихся в альбоме:\n1) 26; 2) 38; 3) 20; 4) 37; 5) 39.`,
[{t:'5',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'4',c:false}],
1,2020);
// A9 — координаты точки, симметричной A относительно l [РИСУНОК; ответ: 3 — (-2;1)]
q(T.geometry,`A9. На координатной плоскости даны точка \\(A\\), расположенная в узле сетки, и прямая \\(l\\) (см. рис.). Определите координаты точки, симметричной точке \\(A\\) относительно прямой \\(l\\):\n1) \\((1;\\,1)\\); 2) \\((-1;\\,0)\\); 3) \\((-2;\\,1)\\); 4) \\((0;\\,2)\\); 5) \\((-2;\\,4)\\).`,
[{t:'3',c:true},{t:'1',c:false},{t:'2',c:false},{t:'4',c:false},{t:'5',c:false}],
1,2020,'/img/ct/math/2020_v1_a9.png');
// A10 — найти a если 1,8x-0,6y=a проходит через A(-2;9) (ответ: 1 — -9)
q(T.functions,`График уравнения \\(1{,}8x-0{,}6y=a\\) проходит через точку \\(A(-2;\\,9)\\). Найдите число \\(a\\):\n1) \\(-9\\); 2) 9; 3) 7; 4) \\(-18\\); 5) \\(-2{,}4\\).`,
[{t:'1',c:true},{t:'2',c:false},{t:'3',c:false},{t:'4',c:false},{t:'5',c:false}],
1,2020);
// A11 — через сколько минут плот прибудет в пункт отправления катера [РИСУНОК; ответ: 2 — 960 мин]
q(T.word,`A11. Из двух пунктов одновременно навстречу друг другу с постоянными скоростями отправляются по течению реки плот (I) и против течения реки катер (II). На рисунке приведены графики их движения. Определите, через сколько минут от начала движения плот прибудет в пункт, из которого отправился катер:\n1) 1020 мин; 2) 960 мин; 3) 510 мин; 4) 900 мин; 5) 480 мин.`,
[{t:'2',c:true},{t:'1',c:false},{t:'3',c:false},{t:'4',c:false},{t:'5',c:false}],
2,2020,'/img/ct/math/2020_v1_a11.png');
// A12 — внести -x под знак ∛ в -x·∛(2x²) (ответ: 3 — -∛(2x^5))
q(T.numbers,`Внесите множитель под знак корня в выражении \\(-x\\cdot\\sqrt[3]{2x^2}\\):\n1) \\(\\sqrt[3]{2x^2}\\); 2) \\(\\sqrt[3]{2x^3}\\); 3) \\(-\\sqrt[3]{2x^5}\\); 4) \\(-\\sqrt[3]{2x}\\); 5) \\(-\\sqrt[3]{2x^{10}}\\).`,
[{t:'3',c:true},{t:'1',c:false},{t:'2',c:false},{t:'4',c:false},{t:'5',c:false}],
1,2020);
// A13 — расстояние от M до центра окружности (r=13, AM=10, MB=12) (ответ: 2 — 7)
q(Tx.circle,`В окружности радиуса 13 проведена хорда \\(AB\\). Точка \\(M\\) делит хорду \\(AB\\) на отрезки длиной 10 и 12. Найдите расстояние от точки \\(M\\) до центра окружности:\n1) 11; 2) 7; 3) 3; 4) 4; 5) 8.`,
[{t:'2',c:true},{t:'1',c:false},{t:'3',c:false},{t:'4',c:false},{t:'5',c:false}],
2,2020);
// A14 — верное утверждение для (8-x)(x+3)≥0 (ответ: 3 — 4 есть решение)
q(T.inequalities,`Для неравенства \\((8-x)(x+3)\\geq0\\) укажите номер верного утверждения:\n1) равносильно \\(|x|\\geq8\\);\n2) количество целых решений равно 12;\n3) 4 есть решение;\n4) ложно при \\(x\\in(-\\infty;8)\\);\n5) решением является промежуток \\([-8;\\,3]\\).`,
[{t:'3',c:true},{t:'1',c:false},{t:'2',c:false},{t:'4',c:false},{t:'5',c:false}],
2,2020);
// A15 — площадь ромба (диагонали — корни 0,1x²-2,2x+7,4=0) (ответ: 5 — 37)
q(T.geometry,`Длины диагоналей ромба являются корнями уравнения \\(0{,}1x^2-2{,}2x+7{,}4=0\\). Составьте площадь ромба:\n1) 22; 2) 48; 3) 74; 4) 11; 5) 37.`,
[{t:'5',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'4',c:false}],
1,2020);
// A16 — радиус r окружности через A(OA=1,7), B(OB=a), касающейся другой стороны прямого угла (ответ: 1)
q(Tx.circle,`На одной стороне прямого угла \\(O\\) отмечены точки \\(A\\) и \\(B\\), \\(OA=1{,}7\\), \\(OB=a\\), \\(OA<OB\\). Составьте формулу радиуса \\(r\\) окружности, проходящей через \\(A\\), \\(B\\) и касающейся другой стороны прямого угла:\n1) \\(r=\\dfrac{a+1{,}7}{2}\\); 2) \\(r=\\dfrac{a-1{,}7}{2}\\); 3) \\(r=a+1{,}7\\); 4) \\(r=\\dfrac{a+3{,}4}{2}\\); 5) \\(r=2a-1{,}7\\).`,
[{t:'1',c:true},{t:'2',c:false},{t:'3',c:false},{t:'4',c:false},{t:'5',c:false}],
2,2020);
// A17 — число B, если округление до сотых A=5,43 и |A-B|=5·10⁻³ (ответ: 3 — 5,425)
q(T.numbers,`Число \\(A=5{,}43\\) является результатом округления числа \\(B\\) до сотых. Если \\(|A-B|=5\\cdot10^{-3}\\), то число \\(B\\) равно:\n1) 5,4295; 2) 5,4305; 3) 5,425; 4) 5,435; 5) 5,4350.`,
[{t:'3',c:true},{t:'1',c:false},{t:'2',c:false},{t:'4',c:false},{t:'5',c:false}],
1,2020);
// A18 — объём цилиндра h=3r, r=√6 (ответ: 5)
q(T.geometry,`Высота цилиндра в 3 раза больше радиуса его основания. Найдите объём цилиндра, если радиус основания равен \\(\\sqrt{6}\\):\n1) \\(5\\sqrt{6}\\pi\\); 2) \\(54\\sqrt{6}\\pi\\); 3) \\(9\\sqrt{6}\\pi\\); 4) \\(18\\sqrt{6}\\pi\\); 5) \\(18\\pi\\sqrt{6}\\).`,
[{t:'5',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'4',c:false}],
1,2020);
// A19 — произведение наим. целого решения на кол-во целых решений |x²+9x|≤10 (ответ: 4 — -60)
q(T.inequalities,`Найдите произведение наименьшего целого решения на количество всех целых решений неравенства \\(|x^2+9x|\\leq10\\):\n1) 90; 2) \\(-54\\); 3) 60; 4) \\(-60\\); 5) \\(-90\\).`,
[{t:'4',c:true},{t:'1',c:false},{t:'2',c:false},{t:'3',c:false},{t:'5',c:false}],
2,2020);
// A20 — длина отрезка пересечения плоскости N,M,B с основанием ABCD [РИСУНОК; ответ: 1 — 37√13/3]
q(Tx.stereo,`A20. \\(SABCD\\) — правильная четырёхугольная пирамида, все рёбра которой равны 37. Точка \\(M\\) — середина ребра \\(SA\\). Точка \\(N\\in SD\\), \\(DN:NS=1:3\\). Найдите длину отрезка, по которому плоскость через \\(N\\), \\(M\\), \\(B\\) пересекает основание \\(ABCD\\):\n1) \\(\\dfrac{37\\sqrt{13}}{3}\\); 2) \\(46\\dfrac{1}{4}\\); 3) \\(\\dfrac{37\\sqrt{10}}{3}\\); 4) \\(\\dfrac{37\\sqrt{17}}{4}\\); 5) \\(\\dfrac{37\\sqrt{5}}{2}\\).`,
[{t:'1',c:true},{t:'2',c:false},{t:'3',c:false},{t:'4',c:false},{t:'5',c:false}],
3,2020,'/img/ct/math/2020_v1_a20.png');
// ══ ЧАСТЬ B ══════════════════════════════════════════════════
// B1 — АП a₅-a₁=12, a₁₀=14: разность/первый член/S₈ → А6Б2В5
fb(T.progression,`B1. Дана арифметическая прогрессия \\((a_n)\\), у которой \\(a_5-a_1=12\\), \\(a_{10}=14\\). Для начала каждого предложения А–В подберите окончание 1–6 (d; a₁; S₈):\nОкончания: 1)2; 2)13; 3)4; 4)26; 5)20; 6)3.`,
'А6Б2В5',2,2020);
// B2 — выбрать 3 верных утверждения (sin,tg,ctg,cos) → 135
fb(T.trig,`B2. Выберите три верных утверждения, если известно, что \\(\\sin(-23°)=-\\cos67°\\):\n1)\\(\\sin(\\alpha+23°)=0\\); 2)\\(\\mathrm{tg}\\,\\alpha>0\\); 3)\\(\\mathrm{ctg}\\,\\alpha<0\\); 4)\\(\\alpha\\) — угол 1-й четверти; 5)\\(\\sin^2\\!\\alpha+\\cos^2\\!23°=1\\); 6)\\(\\alpha=-23°\\).`,
'135',2,2020);
// B3 — яблоки: 3 корзины по x, +19 < 2x, +19+23 > 3x → x=20
fb(T.word,`В каждую из трёх корзин положили одинаковое количество яблок. Если в одну из корзин добавить 19 яблок, то в ней их окажется меньше, чем в двух других корзинах вместе. Если в эту корзину добавить ещё 23 яблока, то в ней их станет больше, чем было первоначально в трёх корзинах вместе. Сколько яблок было в каждой корзине первоначально?`,
20,2,2020);
// B4 — периметр равнобедренной трапеции (S=115, вписанная окружность r=5) → 46
fb(T.geometry,`В равнобедренной трапеции, площадь которой равна 115, вписана окружность радиуса 5. Найдите периметр трапеции.`,
46,2,2020);
// B5 — наим. (в градусах) × кол-во корней sin5x=cos65° на [-90°;90°] → -335
fb(T.trig,`Найдите произведение наименьшего числа (в градусах) на количество различных корней уравнения \\(\\sin5x=\\cos65°\\) на промежутке \\([-90°;\\,90°]\\).`,
-335,2,2020);
// B6 — площадь ABCD (AN:NB=AM:MD=1:2, S(CMN)=45) → 162
fb(T.geometry,`Точки \\(N\\) и \\(M\\) лежат на сторонах \\(AB\\) и \\(AD\\) параллелограмма \\(ABCD\\) так, что \\(AN:NB=1:2\\), \\(AM:MD=1:2\\). Площадь треугольника \\(CMN\\) равна 45. Найдите площадь параллелограмма \\(ABCD\\).`,
162,2,2020);
// B7 — наим.отриц.цел. × наим.цел.полож. для 3·16^((x²−28)/(x1))10·16^(x/(6x))>8 → -32
fb(T.inequalities,`Найдите произведение наименьшего отрицательного целого и наименьшего целого положительного решений неравенства \\(3\\cdot16^{\\frac{x^2-28}{x-1}}-10\\cdot16^{\\frac{-x}{6x}}>8\\).`,
-32,3,2020);
// B8 — сумма корней ∛(x²+3x−40)·∛(x²−3x40)=0 → -320
fb(T.equations,`Найдите сумму корней (корень, если он единственный) уравнения \\(\\sqrt[3]{x^2+3x-40}\\cdot\\sqrt[3]{x^2-3x-40}=0\\).`,
-320,3,2020);
// B9 — -36/cos²φ (призма ABCA₁B₁C₁, AB=AA₁=5, P,Q — середины AB и A₁C₁) → 160
fb(Tx.stereo,`\\(ABCA_1B_1C_1\\) — правильная треугольная призма, \\(AB=5\\), \\(AA_1=5\\). Точки \\(P\\) и \\(Q\\) — середины рёбер \\(AB\\) и \\(A_1C_1\\) соответственно. Найдите значение \\(-\\dfrac{36}{\\cos^2\\!\\varphi}\\), где \\(\\varphi\\) — угол между \\(PQ\\) и \\(AB_1\\).`,
160,3,2020);
// B10 — сумма квадратов корней log₁₀(17−x)²=22·log₁₀x → 577
fb(T.log,`Найдите сумму квадратов корней (корень, если он единственный) уравнения \\(\\log_{10}(17-x)^2=2-2\\cdot\\log_{10}x\\).`,
577,3,2020);
// B11 — km₀ для пар (m,n): m²+2n=n²−6n+13 → -16
fb(T.equations,`Найдите все пары \\((m,n)\\) целых чисел, связанные соотношением \\(m^2+2n=n^2-6n+13\\). Пусть \\(k\\) — количество таких пар, \\(m_0\\) — наименьшее значение \\(m\\). Найдите \\(k-m_0\\).`,
-16,3,2020);
// B12 — S/π для сферы через B, D₁, серед. BB₁ и CC₁ куба с ребром 4√6 → 336
fb(Tx.stereo,`\\(ABCDA_1B_1C_1D_1\\) — куб, длина ребра \\(4\\sqrt{6}\\). Сфера проходит через вершины \\(B\\) и \\(D_1\\) и середины рёбер \\(BB_1\\) и \\(CC_1\\). Найдите площадь сферы \\(S\\) и запишите значение \\(\\dfrac{S}{\\pi}\\).`,
336,3,2020);
});
run();
console.log(`ЦТ 2020 V1: добавлено ${added}, пропущено (дубликаты) ${skipped}`);