Штуки
Some checks failed
Build and Push Docker Images / build (src/LiquidCode.Tester.Gateway/Dockerfile, git.nullptr.top/liquidcode/liquidcode-tester-gateway-roman, gateway) (push) Successful in 1m12s
Build and Push Docker Images / build (src/LiquidCode.Tester.Worker/Dockerfile, git.nullptr.top/liquidcode/liquidcode-tester-worker-roman, worker) (push) Has been cancelled

This commit is contained in:
2025-11-02 19:31:34 +03:00
parent 50a94ae2be
commit e154890897
103 changed files with 11185 additions and 155 deletions

View File

@@ -2,7 +2,7 @@ name: Build and Push Docker Images
on: on:
push: push:
branches: [ master ] branches: [ roman ]
env: env:
REGISTRY: git.nullptr.top REGISTRY: git.nullptr.top
@@ -16,10 +16,10 @@ jobs:
include: include:
- service: gateway - service: gateway
dockerfile: src/LiquidCode.Tester.Gateway/Dockerfile dockerfile: src/LiquidCode.Tester.Gateway/Dockerfile
image: git.nullptr.top/liquidcode/liquidcode-tester-gateway image: git.nullptr.top/liquidcode/liquidcode-tester-gateway-roman
- service: worker - service: worker
dockerfile: src/LiquidCode.Tester.Worker/Dockerfile dockerfile: src/LiquidCode.Tester.Worker/Dockerfile
image: git.nullptr.top/liquidcode/liquidcode-tester-worker image: git.nullptr.top/liquidcode/liquidcode-tester-worker-roman
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4

57
exam-queue-17/check.cpp Normal file
View File

@@ -0,0 +1,57 @@
#include "testlib.h"
#include <sstream>
using namespace std;
int main(int argc, char * argv[])
{
setName("compare ordered sequences of signed int%d numbers", 8 * int(sizeof(long long)));
registerTestlibCmd(argc, argv);
int n = 0;
string firstElems;
while (!ans.seekEof() && !ouf.seekEof())
{
n++;
long long j = ans.readLong();
long long p = ouf.readLong();
if (j != p)
quitf(_wa, "%d%s numbers differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), vtos(j).c_str(), vtos(p).c_str());
else
if (n <= 5)
{
if (firstElems.length() > 0)
firstElems += " ";
firstElems += vtos(j);
}
}
int extraInAnsCount = 0;
while (!ans.seekEof())
{
ans.readLong();
extraInAnsCount++;
}
int extraInOufCount = 0;
while (!ouf.seekEof())
{
ouf.readLong();
extraInOufCount++;
}
if (extraInAnsCount > 0)
quitf(_wa, "Answer contains longer sequence [length = %d], but output contains %d elements", n + extraInAnsCount, n);
if (extraInOufCount > 0)
quitf(_wa, "Output contains longer sequence [length = %d], but answer contains %d elements", n + extraInOufCount, n);
if (n <= 5)
quitf(_ok, "%d number(s): \"%s\"", n, compress(firstElems).c_str());
else
quitf(_ok, "%d numbers", n);
}

BIN
exam-queue-17/check.exe Normal file

Binary file not shown.

108
exam-queue-17/doall.bat Normal file
View File

@@ -0,0 +1,108 @@
rem *** validation ***
call scripts\run-validator-tests.bat
call scripts\run-checker-tests.bat
rem *** tests ***
md tests
call scripts\gen-input-via-stdout.bat "files\gen.exe 1 5 10 5 10 1 100" "tests\02" 2
call scripts\gen-input-via-stdout.bat "files\gen.exe 2 5 10 5 10 1 100" "tests\03" 3
call scripts\gen-input-via-stdout.bat "files\gen.exe 3 5 10 5 10 1 100" "tests\04" 4
call scripts\gen-input-via-stdout.bat "files\gen.exe 4 5 10 5 10 1 100" "tests\05" 5
call scripts\gen-input-via-stdout.bat "files\gen.exe 5 5 10 5 10 1 100" "tests\06" 6
call scripts\gen-input-via-stdout.bat "files\gen.exe 1 50 100 500 1000 1 1000000" "tests\07" 7
call scripts\gen-input-via-stdout.bat "files\gen.exe 2 50 100 500 1000 1 1000000" "tests\08" 8
call scripts\gen-input-via-stdout.bat "files\gen.exe 3 50 100 500 1000 1 1000000" "tests\09" 9
call scripts\gen-input-via-stdout.bat "files\gen.exe 4 50 100 500 1000 1 1000000" "tests\10" 10
call scripts\gen-input-via-stdout.bat "files\gen.exe 5 50 100 500 1000 1 1000000" "tests\11" 11
call scripts\gen-input-via-stdout.bat "files\gen.exe 1 50000 100000 50000 100000 1 1000000000" "tests\12" 12
call scripts\gen-input-via-stdout.bat "files\gen.exe 2 50000 100000 50000 100000 1 1000000000" "tests\13" 13
call scripts\gen-input-via-stdout.bat "files\gen.exe 3 50000 100000 50000 100000 1 1000000000" "tests\14" 14
call scripts\gen-input-via-stdout.bat "files\gen.exe 4 50000 100000 50000 100000 1 1000000000" "tests\15" 15
call scripts\gen-input-via-stdout.bat "files\gen.exe 5 50000 100000 50000 100000 1 1000000000" "tests\16" 16
call scripts\gen-input-via-stdout.bat "files\gen.exe 6 50000 100000 50000 100000 1 1000000000" "tests\17" 17
call scripts\gen-input-via-stdout.bat "files\gen.exe 7 50000 100000 50000 100000 1 1000000000" "tests\18" 18
call scripts\gen-input-via-stdout.bat "files\gen.exe 8 50000 100000 50000 100000 1 1000000000" "tests\19" 19
call scripts\gen-input-via-stdout.bat "files\gen.exe 9 50000 100000 50000 100000 1 1000000000" "tests\20" 20
call scripts\gen-input-via-stdout.bat "files\gen.exe 10 50000 100000 50000 100000 1 1000000000" "tests\21" 21
call scripts\gen-input-via-stdout.bat "files\gen.exe 1 100000 100000 100000 100000 1 1000000000" "tests\22" 22
call scripts\gen-input-via-stdout.bat "files\gen.exe 2 100000 100000 100000 100000 1 1000000000" "tests\23" 23
call scripts\gen-input-via-stdout.bat "files\gen.exe 3 100000 100000 100000 100000 1 1000000000" "tests\24" 24
call scripts\gen-input-via-stdout.bat "files\gen.exe 4 100000 100000 100000 100000 1 1000000000" "tests\25" 25
call scripts\gen-input-via-stdout.bat "files\gen.exe 5 100000 100000 100000 100000 1 1000000000" "tests\26" 26
call scripts\gen-input-via-stdout.bat "files\gen.exe 6 100000 100000 100000 100000 1 1000000000" "tests\27" 27
call scripts\gen-input-via-stdout.bat "files\gen.exe 7 100000 100000 100000 100000 1 1000000000" "tests\28" 28
call scripts\gen-input-via-stdout.bat "files\gen.exe 8 100000 100000 100000 100000 1 1000000000" "tests\29" 29
call scripts\gen-input-via-stdout.bat "files\gen.exe 9 100000 100000 100000 100000 1 1000000000" "tests\30" 30
call scripts\gen-input-via-stdout.bat "files\gen.exe 10 100000 100000 100000 100000 1 1000000000" "tests\31" 31
call scripts\gen-input-via-stdout.bat "files\gen1.exe 1 100000 100000 100000 100000 1 1000000000" "tests\32" 32
call scripts\gen-input-via-stdout.bat "files\gen1.exe 2 100000 100000 100000 100000 1 1000000000" "tests\33" 33
call scripts\gen-input-via-stdout.bat "files\gen1.exe 3 100000 100000 100000 100000 1 1000000000" "tests\34" 34
call scripts\gen-input-via-stdout.bat "files\gen1.exe 4 100000 100000 100000 100000 1 1000000000" "tests\35" 35
call scripts\gen-input-via-stdout.bat "files\gen1.exe 5 100000 100000 100000 100000 1 1000000000" "tests\36" 36
call scripts\gen-input-via-stdout.bat "files\gen2.exe 1 100000 100000 100000 100000 1 1000000000" "tests\37" 37
call scripts\gen-input-via-stdout.bat "files\gen2.exe 2 100000 100000 100000 100000 1 1000000000" "tests\38" 38
call scripts\gen-input-via-stdout.bat "files\gen2.exe 3 100000 100000 100000 100000 1 1000000000" "tests\39" 39
call scripts\gen-input-via-stdout.bat "files\gen2.exe 4 100000 100000 100000 100000 1 1000000000" "tests\40" 40
call scripts\gen-input-via-stdout.bat "files\gen2.exe 5 100000 100000 100000 100000 1 1000000000" "tests\41" 41
call scripts\gen-input-via-stdout.bat "files\print.exe 1" "tests\42" 42
call scripts\gen-input-via-stdout.bat "files\print.exe 2" "tests\43" 43
call scripts\gen-input-via-stdout.bat "files\print.exe 3" "tests\44" 44
call scripts\gen-input-via-stdout.bat "files\print.exe 4" "tests\45" 45
call scripts\gen-input-via-stdout.bat "files\print.exe 5" "tests\46" 46
call scripts\gen-input-via-stdout.bat "files\print.exe 6" "tests\47" 47
call scripts\gen-input-via-stdout.bat "files\print.exe 7" "tests\48" 48
call scripts\gen-input-via-stdout.bat "files\print.exe 8" "tests\49" 49
call scripts\gen-input-via-stdout.bat "files\print.exe 9" "tests\50" 50
call scripts\gen-input-via-stdout.bat "files\print.exe 10" "tests\51" 51
call scripts\gen-answer.bat tests\01 tests\01.a "tests" "SAMPLES"
call scripts\gen-answer.bat tests\02 tests\02.a "tests" "POINTS"
call scripts\gen-answer.bat tests\03 tests\03.a "tests" "POINTS"
call scripts\gen-answer.bat tests\04 tests\04.a "tests" "POINTS"
call scripts\gen-answer.bat tests\05 tests\05.a "tests" "POINTS"
call scripts\gen-answer.bat tests\06 tests\06.a "tests" "POINTS"
call scripts\gen-answer.bat tests\07 tests\07.a "tests" "POINTS"
call scripts\gen-answer.bat tests\08 tests\08.a "tests" "POINTS"
call scripts\gen-answer.bat tests\09 tests\09.a "tests" "POINTS"
call scripts\gen-answer.bat tests\10 tests\10.a "tests" "POINTS"
call scripts\gen-answer.bat tests\11 tests\11.a "tests" "POINTS"
call scripts\gen-answer.bat tests\12 tests\12.a "tests" "POINTS"
call scripts\gen-answer.bat tests\13 tests\13.a "tests" "POINTS"
call scripts\gen-answer.bat tests\14 tests\14.a "tests" "POINTS"
call scripts\gen-answer.bat tests\15 tests\15.a "tests" "POINTS"
call scripts\gen-answer.bat tests\16 tests\16.a "tests" "POINTS"
call scripts\gen-answer.bat tests\17 tests\17.a "tests" "POINTS"
call scripts\gen-answer.bat tests\18 tests\18.a "tests" "POINTS"
call scripts\gen-answer.bat tests\19 tests\19.a "tests" "POINTS"
call scripts\gen-answer.bat tests\20 tests\20.a "tests" "POINTS"
call scripts\gen-answer.bat tests\21 tests\21.a "tests" "POINTS"
call scripts\gen-answer.bat tests\22 tests\22.a "tests" "POINTS"
call scripts\gen-answer.bat tests\23 tests\23.a "tests" "POINTS"
call scripts\gen-answer.bat tests\24 tests\24.a "tests" "POINTS"
call scripts\gen-answer.bat tests\25 tests\25.a "tests" "POINTS"
call scripts\gen-answer.bat tests\26 tests\26.a "tests" "POINTS"
call scripts\gen-answer.bat tests\27 tests\27.a "tests" "POINTS"
call scripts\gen-answer.bat tests\28 tests\28.a "tests" "POINTS"
call scripts\gen-answer.bat tests\29 tests\29.a "tests" "POINTS"
call scripts\gen-answer.bat tests\30 tests\30.a "tests" "POINTS"
call scripts\gen-answer.bat tests\31 tests\31.a "tests" "POINTS"
call scripts\gen-answer.bat tests\32 tests\32.a "tests" "POINTS"
call scripts\gen-answer.bat tests\33 tests\33.a "tests" "POINTS"
call scripts\gen-answer.bat tests\34 tests\34.a "tests" "POINTS"
call scripts\gen-answer.bat tests\35 tests\35.a "tests" "POINTS"
call scripts\gen-answer.bat tests\36 tests\36.a "tests" "POINTS"
call scripts\gen-answer.bat tests\37 tests\37.a "tests" "POINTS"
call scripts\gen-answer.bat tests\38 tests\38.a "tests" "POINTS"
call scripts\gen-answer.bat tests\39 tests\39.a "tests" "POINTS"
call scripts\gen-answer.bat tests\40 tests\40.a "tests" "POINTS"
call scripts\gen-answer.bat tests\41 tests\41.a "tests" "POINTS"
call scripts\gen-answer.bat tests\42 tests\42.a "tests" "POINTS"
call scripts\gen-answer.bat tests\43 tests\43.a "tests" "POINTS"
call scripts\gen-answer.bat tests\44 tests\44.a "tests" "POINTS"
call scripts\gen-answer.bat tests\45 tests\45.a "tests" "POINTS"
call scripts\gen-answer.bat tests\46 tests\46.a "tests" "POINTS"
call scripts\gen-answer.bat tests\47 tests\47.a "tests" "POINTS"
call scripts\gen-answer.bat tests\48 tests\48.a "tests" "POINTS"
call scripts\gen-answer.bat tests\49 tests\49.a "tests" "POINTS"
call scripts\gen-answer.bat tests\50 tests\50.a "tests" "POINTS"
call scripts\gen-answer.bat tests\51 tests\51.a "tests" "POINTS"

262
exam-queue-17/doall.sh Normal file
View File

@@ -0,0 +1,262 @@
#!/usr/bin/env bash
# *** validation ***
scripts/run-validator-tests.sh
scripts/run-checker-tests.sh
# *** tests ***
mkdir -p tests
echo "Generating test #2"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 1 5 10 5 10 1 100" "tests/02" 2
echo "Generating test #3"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 2 5 10 5 10 1 100" "tests/03" 3
echo "Generating test #4"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 3 5 10 5 10 1 100" "tests/04" 4
echo "Generating test #5"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 4 5 10 5 10 1 100" "tests/05" 5
echo "Generating test #6"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 5 5 10 5 10 1 100" "tests/06" 6
echo "Generating test #7"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 1 50 100 500 1000 1 1000000" "tests/07" 7
echo "Generating test #8"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 2 50 100 500 1000 1 1000000" "tests/08" 8
echo "Generating test #9"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 3 50 100 500 1000 1 1000000" "tests/09" 9
echo "Generating test #10"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 4 50 100 500 1000 1 1000000" "tests/10" 10
echo "Generating test #11"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 5 50 100 500 1000 1 1000000" "tests/11" 11
echo "Generating test #12"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 1 50000 100000 50000 100000 1 1000000000" "tests/12" 12
echo "Generating test #13"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 2 50000 100000 50000 100000 1 1000000000" "tests/13" 13
echo "Generating test #14"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 3 50000 100000 50000 100000 1 1000000000" "tests/14" 14
echo "Generating test #15"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 4 50000 100000 50000 100000 1 1000000000" "tests/15" 15
echo "Generating test #16"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 5 50000 100000 50000 100000 1 1000000000" "tests/16" 16
echo "Generating test #17"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 6 50000 100000 50000 100000 1 1000000000" "tests/17" 17
echo "Generating test #18"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 7 50000 100000 50000 100000 1 1000000000" "tests/18" 18
echo "Generating test #19"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 8 50000 100000 50000 100000 1 1000000000" "tests/19" 19
echo "Generating test #20"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 9 50000 100000 50000 100000 1 1000000000" "tests/20" 20
echo "Generating test #21"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 10 50000 100000 50000 100000 1 1000000000" "tests/21" 21
echo "Generating test #22"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 1 100000 100000 100000 100000 1 1000000000" "tests/22" 22
echo "Generating test #23"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 2 100000 100000 100000 100000 1 1000000000" "tests/23" 23
echo "Generating test #24"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 3 100000 100000 100000 100000 1 1000000000" "tests/24" 24
echo "Generating test #25"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 4 100000 100000 100000 100000 1 1000000000" "tests/25" 25
echo "Generating test #26"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 5 100000 100000 100000 100000 1 1000000000" "tests/26" 26
echo "Generating test #27"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 6 100000 100000 100000 100000 1 1000000000" "tests/27" 27
echo "Generating test #28"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 7 100000 100000 100000 100000 1 1000000000" "tests/28" 28
echo "Generating test #29"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 8 100000 100000 100000 100000 1 1000000000" "tests/29" 29
echo "Generating test #30"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 9 100000 100000 100000 100000 1 1000000000" "tests/30" 30
echo "Generating test #31"
scripts/gen-input-via-stdout.sh "wine files/gen.exe 10 100000 100000 100000 100000 1 1000000000" "tests/31" 31
echo "Generating test #32"
scripts/gen-input-via-stdout.sh "wine files/gen1.exe 1 100000 100000 100000 100000 1 1000000000" "tests/32" 32
echo "Generating test #33"
scripts/gen-input-via-stdout.sh "wine files/gen1.exe 2 100000 100000 100000 100000 1 1000000000" "tests/33" 33
echo "Generating test #34"
scripts/gen-input-via-stdout.sh "wine files/gen1.exe 3 100000 100000 100000 100000 1 1000000000" "tests/34" 34
echo "Generating test #35"
scripts/gen-input-via-stdout.sh "wine files/gen1.exe 4 100000 100000 100000 100000 1 1000000000" "tests/35" 35
echo "Generating test #36"
scripts/gen-input-via-stdout.sh "wine files/gen1.exe 5 100000 100000 100000 100000 1 1000000000" "tests/36" 36
echo "Generating test #37"
scripts/gen-input-via-stdout.sh "wine files/gen2.exe 1 100000 100000 100000 100000 1 1000000000" "tests/37" 37
echo "Generating test #38"
scripts/gen-input-via-stdout.sh "wine files/gen2.exe 2 100000 100000 100000 100000 1 1000000000" "tests/38" 38
echo "Generating test #39"
scripts/gen-input-via-stdout.sh "wine files/gen2.exe 3 100000 100000 100000 100000 1 1000000000" "tests/39" 39
echo "Generating test #40"
scripts/gen-input-via-stdout.sh "wine files/gen2.exe 4 100000 100000 100000 100000 1 1000000000" "tests/40" 40
echo "Generating test #41"
scripts/gen-input-via-stdout.sh "wine files/gen2.exe 5 100000 100000 100000 100000 1 1000000000" "tests/41" 41
echo "Generating test #42"
scripts/gen-input-via-stdout.sh "wine files/print.exe 1" "tests/42" 42
echo "Generating test #43"
scripts/gen-input-via-stdout.sh "wine files/print.exe 2" "tests/43" 43
echo "Generating test #44"
scripts/gen-input-via-stdout.sh "wine files/print.exe 3" "tests/44" 44
echo "Generating test #45"
scripts/gen-input-via-stdout.sh "wine files/print.exe 4" "tests/45" 45
echo "Generating test #46"
scripts/gen-input-via-stdout.sh "wine files/print.exe 5" "tests/46" 46
echo "Generating test #47"
scripts/gen-input-via-stdout.sh "wine files/print.exe 6" "tests/47" 47
echo "Generating test #48"
scripts/gen-input-via-stdout.sh "wine files/print.exe 7" "tests/48" 48
echo "Generating test #49"
scripts/gen-input-via-stdout.sh "wine files/print.exe 8" "tests/49" 49
echo "Generating test #50"
scripts/gen-input-via-stdout.sh "wine files/print.exe 9" "tests/50" 50
echo "Generating test #51"
scripts/gen-input-via-stdout.sh "wine files/print.exe 10" "tests/51" 51
echo ""
echo "Generating answer for test #1"
scripts/gen-answer.sh tests/01 tests/01.a "tests" "SAMPLES"
echo ""
echo "Generating answer for test #2"
scripts/gen-answer.sh tests/02 tests/02.a "tests" "POINTS"
echo ""
echo "Generating answer for test #3"
scripts/gen-answer.sh tests/03 tests/03.a "tests" "POINTS"
echo ""
echo "Generating answer for test #4"
scripts/gen-answer.sh tests/04 tests/04.a "tests" "POINTS"
echo ""
echo "Generating answer for test #5"
scripts/gen-answer.sh tests/05 tests/05.a "tests" "POINTS"
echo ""
echo "Generating answer for test #6"
scripts/gen-answer.sh tests/06 tests/06.a "tests" "POINTS"
echo ""
echo "Generating answer for test #7"
scripts/gen-answer.sh tests/07 tests/07.a "tests" "POINTS"
echo ""
echo "Generating answer for test #8"
scripts/gen-answer.sh tests/08 tests/08.a "tests" "POINTS"
echo ""
echo "Generating answer for test #9"
scripts/gen-answer.sh tests/09 tests/09.a "tests" "POINTS"
echo ""
echo "Generating answer for test #10"
scripts/gen-answer.sh tests/10 tests/10.a "tests" "POINTS"
echo ""
echo "Generating answer for test #11"
scripts/gen-answer.sh tests/11 tests/11.a "tests" "POINTS"
echo ""
echo "Generating answer for test #12"
scripts/gen-answer.sh tests/12 tests/12.a "tests" "POINTS"
echo ""
echo "Generating answer for test #13"
scripts/gen-answer.sh tests/13 tests/13.a "tests" "POINTS"
echo ""
echo "Generating answer for test #14"
scripts/gen-answer.sh tests/14 tests/14.a "tests" "POINTS"
echo ""
echo "Generating answer for test #15"
scripts/gen-answer.sh tests/15 tests/15.a "tests" "POINTS"
echo ""
echo "Generating answer for test #16"
scripts/gen-answer.sh tests/16 tests/16.a "tests" "POINTS"
echo ""
echo "Generating answer for test #17"
scripts/gen-answer.sh tests/17 tests/17.a "tests" "POINTS"
echo ""
echo "Generating answer for test #18"
scripts/gen-answer.sh tests/18 tests/18.a "tests" "POINTS"
echo ""
echo "Generating answer for test #19"
scripts/gen-answer.sh tests/19 tests/19.a "tests" "POINTS"
echo ""
echo "Generating answer for test #20"
scripts/gen-answer.sh tests/20 tests/20.a "tests" "POINTS"
echo ""
echo "Generating answer for test #21"
scripts/gen-answer.sh tests/21 tests/21.a "tests" "POINTS"
echo ""
echo "Generating answer for test #22"
scripts/gen-answer.sh tests/22 tests/22.a "tests" "POINTS"
echo ""
echo "Generating answer for test #23"
scripts/gen-answer.sh tests/23 tests/23.a "tests" "POINTS"
echo ""
echo "Generating answer for test #24"
scripts/gen-answer.sh tests/24 tests/24.a "tests" "POINTS"
echo ""
echo "Generating answer for test #25"
scripts/gen-answer.sh tests/25 tests/25.a "tests" "POINTS"
echo ""
echo "Generating answer for test #26"
scripts/gen-answer.sh tests/26 tests/26.a "tests" "POINTS"
echo ""
echo "Generating answer for test #27"
scripts/gen-answer.sh tests/27 tests/27.a "tests" "POINTS"
echo ""
echo "Generating answer for test #28"
scripts/gen-answer.sh tests/28 tests/28.a "tests" "POINTS"
echo ""
echo "Generating answer for test #29"
scripts/gen-answer.sh tests/29 tests/29.a "tests" "POINTS"
echo ""
echo "Generating answer for test #30"
scripts/gen-answer.sh tests/30 tests/30.a "tests" "POINTS"
echo ""
echo "Generating answer for test #31"
scripts/gen-answer.sh tests/31 tests/31.a "tests" "POINTS"
echo ""
echo "Generating answer for test #32"
scripts/gen-answer.sh tests/32 tests/32.a "tests" "POINTS"
echo ""
echo "Generating answer for test #33"
scripts/gen-answer.sh tests/33 tests/33.a "tests" "POINTS"
echo ""
echo "Generating answer for test #34"
scripts/gen-answer.sh tests/34 tests/34.a "tests" "POINTS"
echo ""
echo "Generating answer for test #35"
scripts/gen-answer.sh tests/35 tests/35.a "tests" "POINTS"
echo ""
echo "Generating answer for test #36"
scripts/gen-answer.sh tests/36 tests/36.a "tests" "POINTS"
echo ""
echo "Generating answer for test #37"
scripts/gen-answer.sh tests/37 tests/37.a "tests" "POINTS"
echo ""
echo "Generating answer for test #38"
scripts/gen-answer.sh tests/38 tests/38.a "tests" "POINTS"
echo ""
echo "Generating answer for test #39"
scripts/gen-answer.sh tests/39 tests/39.a "tests" "POINTS"
echo ""
echo "Generating answer for test #40"
scripts/gen-answer.sh tests/40 tests/40.a "tests" "POINTS"
echo ""
echo "Generating answer for test #41"
scripts/gen-answer.sh tests/41 tests/41.a "tests" "POINTS"
echo ""
echo "Generating answer for test #42"
scripts/gen-answer.sh tests/42 tests/42.a "tests" "POINTS"
echo ""
echo "Generating answer for test #43"
scripts/gen-answer.sh tests/43 tests/43.a "tests" "POINTS"
echo ""
echo "Generating answer for test #44"
scripts/gen-answer.sh tests/44 tests/44.a "tests" "POINTS"
echo ""
echo "Generating answer for test #45"
scripts/gen-answer.sh tests/45 tests/45.a "tests" "POINTS"
echo ""
echo "Generating answer for test #46"
scripts/gen-answer.sh tests/46 tests/46.a "tests" "POINTS"
echo ""
echo "Generating answer for test #47"
scripts/gen-answer.sh tests/47 tests/47.a "tests" "POINTS"
echo ""
echo "Generating answer for test #48"
scripts/gen-answer.sh tests/48 tests/48.a "tests" "POINTS"
echo ""
echo "Generating answer for test #49"
scripts/gen-answer.sh tests/49 tests/49.a "tests" "POINTS"
echo ""
echo "Generating answer for test #50"
scripts/gen-answer.sh tests/50 tests/50.a "tests" "POINTS"
echo ""
echo "Generating answer for test #51"
scripts/gen-answer.sh tests/51 tests/51.a "tests" "POINTS"
echo ""

View File

@@ -0,0 +1,57 @@
#include "testlib.h"
#include <sstream>
using namespace std;
int main(int argc, char * argv[])
{
setName("compare ordered sequences of signed int%d numbers", 8 * int(sizeof(long long)));
registerTestlibCmd(argc, argv);
int n = 0;
string firstElems;
while (!ans.seekEof() && !ouf.seekEof())
{
n++;
long long j = ans.readLong();
long long p = ouf.readLong();
if (j != p)
quitf(_wa, "%d%s numbers differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), vtos(j).c_str(), vtos(p).c_str());
else
if (n <= 5)
{
if (firstElems.length() > 0)
firstElems += " ";
firstElems += vtos(j);
}
}
int extraInAnsCount = 0;
while (!ans.seekEof())
{
ans.readLong();
extraInAnsCount++;
}
int extraInOufCount = 0;
while (!ouf.seekEof())
{
ouf.readLong();
extraInOufCount++;
}
if (extraInAnsCount > 0)
quitf(_wa, "Answer contains longer sequence [length = %d], but output contains %d elements", n + extraInAnsCount, n);
if (extraInOufCount > 0)
quitf(_wa, "Output contains longer sequence [length = %d], but answer contains %d elements", n + extraInOufCount, n);
if (n <= 5)
quitf(_ok, "%d number(s): \"%s\"", n, compress(firstElems).c_str());
else
quitf(_ok, "%d numbers", n);
}

281
exam-queue-17/files/gen.cpp Normal file
View File

@@ -0,0 +1,281 @@
#include<bits/stdc++.h>
#ifndef KRAKOZYABRA
#include "testlib.h"
#else
#include "testliblochal.h"
#endif // KRAKOZYABRA
using namespace std;
template <typename T>
class ordered_set {
private:
struct Node {
T data;
int weight; // Number of nodes in the subtree rooted at this node
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
Node(const T& data) : data(data), weight(1), left(nullptr), right(nullptr) {}
};
std::unique_ptr<Node> root;
// Helper function to update the weight of a node
void update_weight(Node* node) {
if (node) {
node->weight = 1;
if (node->left) node->weight += node->left->weight;
if (node->right) node->weight += node->right->weight;
}
}
// Helper function for insertion
Node* insert_recursive(Node* node, const T& data) {
if (!node) {
return new Node(data);
}
if (data < node->data) {
node->left.reset(insert_recursive(node->left.release(), data)); //Release ownership before recursive call
}
else {
node->right.reset(insert_recursive(node->right.release(), data)); //Release ownership before recursive call
}
update_weight(node);
return node;
}
// Helper function for deletion (find minimum in right subtree)
Node* find_min(Node* node) {
while (node->left) {
node = node->left.get(); // Access the raw pointer
}
return node;
}
// Helper function for deletion
Node* delete_recursive(Node* node, const T& data) {
if (!node) {
return nullptr; // Value not found
}
if (data < node->data) {
node->left.reset(delete_recursive(node->left.release(), data)); //Release ownership before recursive call
}
else if (data > node->data) {
node->right.reset(delete_recursive(node->right.release(), data)); //Release ownership before recursive call
}
else {
// Node to be deleted found
// Case 1: Node with no child or only one child
if (!node->left) {
Node* temp = node->right.release();
delete node;
return temp;
}
else if (!node->right) {
Node* temp = node->left.release();
delete node;
return temp;
}
// Case 2: Node with two children
Node* temp = find_min(node->right.get());
node->data = temp->data;
node->right.reset(delete_recursive(node->right.release(), temp->data));
}
update_weight(node);
return node;
}
//Helper for get_element_at_index (find the k-th smallest element).
T get_element_at_index_recursive(Node* node, int index) {
if (!node) {
throw std::out_of_range("Index out of range");
}
int left_subtree_size = (node->left) ? node->left->weight : 0;
if (index == left_subtree_size) {
return node->data;
}
else if (index < left_subtree_size) {
return get_element_at_index_recursive(node->left.get(), index);
}
else {
return get_element_at_index_recursive(node->right.get(), index - left_subtree_size - 1);
}
}
//Helper to perform inorder traversal
void inorder_traversal_recursive(Node* node, std::vector<T>& result) const {
if (node) {
inorder_traversal_recursive(node->left.get(), result);
result.push_back(node->data);
inorder_traversal_recursive(node->right.get(), result);
}
}
//Helper to find index of an element.
int get_index_of_element_recursive(Node* node, const T& target, int current_rank) const {
if (!node) {
return -1; // Element not found
}
int left_subtree_size = (node->left) ? node->left->weight : 0;
if (target == node->data) {
return current_rank + left_subtree_size;
}
else if (target < node->data) {
return get_index_of_element_recursive(node->left.get(), target, current_rank);
}
else {
return get_index_of_element_recursive(node->right.get(), target, current_rank + left_subtree_size + 1);
}
}
public:
ordered_set() : root(nullptr) {}
void insert(const T& data) {
if (!root) {
root = std::make_unique<Node>(data);
}
else {
root.reset(insert_recursive(root.release(), data)); //Release ownership before recursive call
}
}
void erase(const T& data) {
root.reset(delete_recursive(root.release(), data)); //Release ownership before recursive call
}
T get_element(int index) {
if (index < 0 || index >= size()) {
throw std::out_of_range("Index out of range");
}
return get_element_at_index_recursive(root.get(), index);
}
int size() const {
return (root) ? root->weight : 0;
}
bool empty() const {
return root == nullptr;
}
void clear() {
root.reset(); // Effectively deletes the entire tree
}
// Returns a vector of the elements in sorted order (inorder traversal)
std::vector<T> inorder_traversal() const {
std::vector<T> result;
inorder_traversal_recursive(root.get(), result);
return result;
}
// Added function to get the index of an element
int get_index(const T target) const {
return get_index_of_element_recursive(root.get(), target, 0);
}
};
int main(int argc, char* argv[]) {
#ifndef KRAKOZYABRA
registerGen(argc, argv, 1);
#endif // KRAKOZYABRA
int minN = opt<int>(2), maxN = opt<int>(3);
int minM = opt<int>(4), maxM = opt<int>(5);
int minA = opt<int>(6), maxA = opt<int>(7);
int n = rnd.next(minN, maxN);
int m = rnd.next(minM, maxM);
cout << n << ' ' << m << '\n';
ordered_set<int> st;
vector<int> a;
while (a.size() < n) {
int aa = rnd.next(minA, maxA);
if (st.get_index(aa) == -1) {
a.push_back(aa);
st.insert(aa);
}
}
auto getrndin = [&]() {
if (st.size() == 0)
return -1;
int sz = st.size();
int i = rnd.next(0, sz - 1);
return st.get_element(i);
};
auto getrndnew = [&]() {
int aa = rnd.next(minA, maxA);
while (st.get_index(aa) != -1)
aa = rnd.next(minA, maxA);
return aa;
};
for (int i = 0; i < n; i++)
cout << a[i] << " \n"[i == n - 1];
for (int i = 0; i < m; i++) {
int t = 0;
if (st.size() == 0)
t = 2;
else
t = rnd.next(1, 3);
if (t == 1) {
int x = getrndnew();
int y = getrndin();
st.insert(x);
cout << t << ' ' << x << ' ' << y << '\n';
}
if (t == 2) {
int x = getrndnew();
st.insert(x);
cout << t << ' ' << x << '\n';
}
if (t == 3) {
int x = getrndin();
st.erase(x);
cout << t << ' ' << x << '\n';
}
}
}
//#pragma once
//#include <bits/stdc++.h>
//#include <random>
//#include <optional>
//
//using namespace std;
//
//random_device rd;
//mt19937 gen(rd());
//
//template <typename T>
//T opt(T value) {
// FILE* stream;
// freopen_s(&stream, "params.txt", "r", stdin);
// T res;
// for (int i = 0; i < value; i++)
// cin >> res;
// return res;
//}
//
//class Random {
//public:
// long long next(long long a, long long b) {
// return a + gen() % (b - a + 1);
// };
//};
//
//Random rnd;

BIN
exam-queue-17/files/gen.exe Normal file

Binary file not shown.

View File

@@ -0,0 +1,280 @@
#include<bits/stdc++.h>
#ifndef KRAKOZYABRA
#include "testlib.h"
#else
#include "testliblochal.h"
#endif // KRAKOZYABRA
using namespace std;
template <typename T>
class ordered_set {
private:
struct Node {
T data;
int weight; // Number of nodes in the subtree rooted at this node
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
Node(const T& data) : data(data), weight(1), left(nullptr), right(nullptr) {}
};
std::unique_ptr<Node> root;
// Helper function to update the weight of a node
void update_weight(Node* node) {
if (node) {
node->weight = 1;
if (node->left) node->weight += node->left->weight;
if (node->right) node->weight += node->right->weight;
}
}
// Helper function for insertion
Node* insert_recursive(Node* node, const T& data) {
if (!node) {
return new Node(data);
}
if (data < node->data) {
node->left.reset(insert_recursive(node->left.release(), data)); //Release ownership before recursive call
}
else {
node->right.reset(insert_recursive(node->right.release(), data)); //Release ownership before recursive call
}
update_weight(node);
return node;
}
// Helper function for deletion (find minimum in right subtree)
Node* find_min(Node* node) {
while (node->left) {
node = node->left.get(); // Access the raw pointer
}
return node;
}
// Helper function for deletion
Node* delete_recursive(Node* node, const T& data) {
if (!node) {
return nullptr; // Value not found
}
if (data < node->data) {
node->left.reset(delete_recursive(node->left.release(), data)); //Release ownership before recursive call
}
else if (data > node->data) {
node->right.reset(delete_recursive(node->right.release(), data)); //Release ownership before recursive call
}
else {
// Node to be deleted found
// Case 1: Node with no child or only one child
if (!node->left) {
Node* temp = node->right.release();
delete node;
return temp;
}
else if (!node->right) {
Node* temp = node->left.release();
delete node;
return temp;
}
// Case 2: Node with two children
Node* temp = find_min(node->right.get());
node->data = temp->data;
node->right.reset(delete_recursive(node->right.release(), temp->data));
}
update_weight(node);
return node;
}
//Helper for get_element_at_index (find the k-th smallest element).
T get_element_at_index_recursive(Node* node, int index) {
if (!node) {
throw std::out_of_range("Index out of range");
}
int left_subtree_size = (node->left) ? node->left->weight : 0;
if (index == left_subtree_size) {
return node->data;
}
else if (index < left_subtree_size) {
return get_element_at_index_recursive(node->left.get(), index);
}
else {
return get_element_at_index_recursive(node->right.get(), index - left_subtree_size - 1);
}
}
//Helper to perform inorder traversal
void inorder_traversal_recursive(Node* node, std::vector<T>& result) const {
if (node) {
inorder_traversal_recursive(node->left.get(), result);
result.push_back(node->data);
inorder_traversal_recursive(node->right.get(), result);
}
}
//Helper to find index of an element.
int get_index_of_element_recursive(Node* node, const T& target, int current_rank) const {
if (!node) {
return -1; // Element not found
}
int left_subtree_size = (node->left) ? node->left->weight : 0;
if (target == node->data) {
return current_rank + left_subtree_size;
}
else if (target < node->data) {
return get_index_of_element_recursive(node->left.get(), target, current_rank);
}
else {
return get_index_of_element_recursive(node->right.get(), target, current_rank + left_subtree_size + 1);
}
}
public:
ordered_set() : root(nullptr) {}
void insert(const T& data) {
if (!root) {
root = std::make_unique<Node>(data);
}
else {
root.reset(insert_recursive(root.release(), data)); //Release ownership before recursive call
}
}
void erase(const T& data) {
root.reset(delete_recursive(root.release(), data)); //Release ownership before recursive call
}
T get_element(int index) {
if (index < 0 || index >= size()) {
throw std::out_of_range("Index out of range");
}
return get_element_at_index_recursive(root.get(), index);
}
int size() const {
return (root) ? root->weight : 0;
}
bool empty() const {
return root == nullptr;
}
void clear() {
root.reset(); // Effectively deletes the entire tree
}
// Returns a vector of the elements in sorted order (inorder traversal)
std::vector<T> inorder_traversal() const {
std::vector<T> result;
inorder_traversal_recursive(root.get(), result);
return result;
}
// Added function to get the index of an element
int get_index(const T target) const {
return get_index_of_element_recursive(root.get(), target, 0);
}
};
int main(int argc, char* argv[]) {
#ifndef KRAKOZYABRA
registerGen(argc, argv, 1);
#endif // KRAKOZYABRA
int minN = opt<int>(2), maxN = opt<int>(3);
int minM = opt<int>(4), maxM = opt<int>(5);
int minA = opt<int>(6), maxA = opt<int>(7);
int n = rnd.next(minN, maxN);
int m = rnd.next(minM, maxM);
cout << n << ' ' << m << '\n';
ordered_set<int> st;
vector<int> a;
while (a.size() < n) {
int aa = rnd.next(minA, maxA);
if (st.get_index(aa) == -1) {
a.push_back(aa);
st.insert(aa);
}
}
auto getrndin = [&]() {
if (st.size() == 0)
return -1;
int sz = st.size();
int i = rnd.next(0, sz - 1);
return st.get_element(i);
};
auto getrndnew = [&]() {
int aa = rnd.next(minA, maxA);
while (st.get_index(aa) != -1)
aa = rnd.next(minA, maxA);
return aa;
};
for (int i = 0; i < n; i++)
cout << a[i] << " \n"[i == n - 1];
for (int i = 0; i < m; i++) {
int t = 1;
//if (st.size() == 0)
// t = 2;
//else
// t = rnd.next(1, 3);
if (t == 1) {
int x = getrndnew();
int y = getrndin();
st.insert(x);
cout << t << ' ' << x << ' ' << y << '\n';
}
if (t == 2) {
int x = getrndnew();
st.insert(x);
cout << t << ' ' << x << '\n';
}
if (t == 3) {
int x = getrndin();
st.erase(x);
cout << t << ' ' << x << '\n';
}
}
}
//#pragma once
//#include <bits/stdc++.h>
//#include <random>
//
//using namespace std;
//
//random_device rd;
//mt19937 gen(rd());
//
//template <typename T>
//T opt(T value) {
// FILE* stream;
// freopen_s(&stream, "params.txt", "r", stdin);
// T res;
// for (int i = 0; i < value; i++)
// cin >> res;
// return res;
//}
//
//class Random {
//public:
// long long next(long long a, long long b) {
// return a + gen() % (b - a + 1);
// };
//};
//
//Random rnd;

Binary file not shown.

View File

@@ -0,0 +1,276 @@
#include<bits/stdc++.h>
#ifndef KRAKOZYABRA
#include "testlib.h"
#else
#include "testliblochal.h"
#endif // KRAKOZYABRA
using namespace std;
template <typename T>
class ordered_set {
private:
struct Node {
T data;
int weight; // Number of nodes in the subtree rooted at this node
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
Node(const T& data) : data(data), weight(1), left(nullptr), right(nullptr) {}
};
std::unique_ptr<Node> root;
// Helper function to update the weight of a node
void update_weight(Node* node) {
if (node) {
node->weight = 1;
if (node->left) node->weight += node->left->weight;
if (node->right) node->weight += node->right->weight;
}
}
// Helper function for insertion
Node* insert_recursive(Node* node, const T& data) {
if (!node) {
return new Node(data);
}
if (data < node->data) {
node->left.reset(insert_recursive(node->left.release(), data)); //Release ownership before recursive call
}
else {
node->right.reset(insert_recursive(node->right.release(), data)); //Release ownership before recursive call
}
update_weight(node);
return node;
}
// Helper function for deletion (find minimum in right subtree)
Node* find_min(Node* node) {
while (node->left) {
node = node->left.get(); // Access the raw pointer
}
return node;
}
// Helper function for deletion
Node* delete_recursive(Node* node, const T& data) {
if (!node) {
return nullptr; // Value not found
}
if (data < node->data) {
node->left.reset(delete_recursive(node->left.release(), data)); //Release ownership before recursive call
}
else if (data > node->data) {
node->right.reset(delete_recursive(node->right.release(), data)); //Release ownership before recursive call
}
else {
// Node to be deleted found
// Case 1: Node with no child or only one child
if (!node->left) {
Node* temp = node->right.release();
delete node;
return temp;
}
else if (!node->right) {
Node* temp = node->left.release();
delete node;
return temp;
}
// Case 2: Node with two children
Node* temp = find_min(node->right.get());
node->data = temp->data;
node->right.reset(delete_recursive(node->right.release(), temp->data));
}
update_weight(node);
return node;
}
//Helper for get_element_at_index (find the k-th smallest element).
T get_element_at_index_recursive(Node* node, int index) {
if (!node) {
throw std::out_of_range("Index out of range");
}
int left_subtree_size = (node->left) ? node->left->weight : 0;
if (index == left_subtree_size) {
return node->data;
}
else if (index < left_subtree_size) {
return get_element_at_index_recursive(node->left.get(), index);
}
else {
return get_element_at_index_recursive(node->right.get(), index - left_subtree_size - 1);
}
}
//Helper to perform inorder traversal
void inorder_traversal_recursive(Node* node, std::vector<T>& result) const {
if (node) {
inorder_traversal_recursive(node->left.get(), result);
result.push_back(node->data);
inorder_traversal_recursive(node->right.get(), result);
}
}
//Helper to find index of an element.
int get_index_of_element_recursive(Node* node, const T& target, int current_rank) const {
if (!node) {
return -1; // Element not found
}
int left_subtree_size = (node->left) ? node->left->weight : 0;
if (target == node->data) {
return current_rank + left_subtree_size;
}
else if (target < node->data) {
return get_index_of_element_recursive(node->left.get(), target, current_rank);
}
else {
return get_index_of_element_recursive(node->right.get(), target, current_rank + left_subtree_size + 1);
}
}
public:
ordered_set() : root(nullptr) {}
void insert(const T& data) {
if (!root) {
root = std::make_unique<Node>(data);
}
else {
root.reset(insert_recursive(root.release(), data)); //Release ownership before recursive call
}
}
void erase(const T& data) {
root.reset(delete_recursive(root.release(), data)); //Release ownership before recursive call
}
T get_element(int index) {
if (index < 0 || index >= size()) {
throw std::out_of_range("Index out of range");
}
return get_element_at_index_recursive(root.get(), index);
}
int size() const {
return (root) ? root->weight : 0;
}
bool empty() const {
return root == nullptr;
}
void clear() {
root.reset(); // Effectively deletes the entire tree
}
// Returns a vector of the elements in sorted order (inorder traversal)
std::vector<T> inorder_traversal() const {
std::vector<T> result;
inorder_traversal_recursive(root.get(), result);
return result;
}
// Added function to get the index of an element
int get_index(const T target) const {
return get_index_of_element_recursive(root.get(), target, 0);
}
};
int main(int argc, char* argv[]) {
#ifndef KRAKOZYABRA
registerGen(argc, argv, 1);
#endif // KRAKOZYABRA
int minN = opt<int>(2), maxN = opt<int>(3);
int minM = opt<int>(4), maxM = opt<int>(5);
int minA = opt<int>(6), maxA = opt<int>(7);
int n = rnd.next(minN, maxN);
int m = rnd.next(minM, maxM);
cout << n << ' ' << m << '\n';
ordered_set<int> st;
vector<int> a;
while (a.size() < n) {
int aa = rnd.next(minA, maxA);
if (st.get_index(aa) == -1) {
a.push_back(aa);
st.insert(aa);
}
}
auto getrndin = [&]() {
if (st.size() == 0)
return -1;
int sz = st.size();
int i = rnd.next(0, sz - 1);
return st.get_element(i);
};
auto getrndnew = [&]() {
int aa = rnd.next(minA, maxA);
while (st.get_index(aa) != -1)
aa = rnd.next(minA, maxA);
return aa;
};
for (int i = 0; i < n; i++)
cout << a[i] << " \n"[i == n - 1];
for (int i = 0; i < m; i++) {
int t = rnd.next(1, 2);
if (t == 1) {
int x = getrndnew();
int y = getrndin();
st.insert(x);
cout << t << ' ' << x << ' ' << y << '\n';
}
if (t == 2) {
int x = getrndnew();
st.insert(x);
cout << t << ' ' << x << '\n';
}
if (t == 3) {
int x = getrndin();
st.erase(x);
cout << t << ' ' << x << '\n';
}
}
}
//#pragma once
//#include <bits/stdc++.h>
//#include <random>
//
//using namespace std;
//
//random_device rd;
//mt19937 gen(rd());
//
//template <typename T>
//T opt(T value) {
// FILE* stream;
// freopen_s(&stream, "params.txt", "r", stdin);
// T res;
// for (int i = 0; i < value; i++)
// cin >> res;
// return res;
//}
//
//class Random {
//public:
// long long next(long long a, long long b) {
// return a + gen() % (b - a + 1);
// };
//};
//
//Random rnd;

Binary file not shown.

View File

@@ -0,0 +1,788 @@
%
% Macros for the contest problems
% for MikTeX: use latex.exe
% License: https://github.com/GassaFM/olymp.sty/blob/master/LICENSE
% Authors: https://github.com/GassaFM/olymp.sty/blob/master/AUTHORS
%
\ProvidesPackage{olymp}
\usepackage{verbatim}
\newif\if@landscape\@landscapefalse
\newif\if@russian\@russianfalse
\newif\if@ukrainian\@ukrainianfalse
\newif\if@arabic\@arabicfalse
\DeclareOption{landscape}{
\@landscapetrue
}
\DeclareOption{russian}{
\@russiantrue
}
\DeclareOption{ukrainian}{
\@ukrainiantrue
}
\DeclareOption{arabic}{
\@arabictrue
}
\ProcessOptions\relax
% -- Setup margins --
%
% Tex defines to large margins for our purposes.
% So we redefine this to use paper more efficiently
%
\newlength{\thelinewidth}
\if@landscape
\if@twocolumn
\else
\error Landscape is only supported for two column mode
\fi
\ifcase\@ptsize % 10 pt
\hoffset=-15mm
\voffset=-35mm
\textheight=165mm
\textwidth=272mm
\or % 11 pt
\hoffset=-13mm
\voffset=-36mm
\textheight=166mm
\textwidth=272mm
\or % 12 pt
\hoffset=-12mm
\voffset=-35mm
\textheight=162mm
\textwidth=268mm
\fi
\else
\ifcase\@ptsize % 10 pt
\hoffset=-26.5mm
\voffset=-35mm
\textheight=250mm
\textwidth=175mm
\or % 11 pt
\hoffset=-25mm
\voffset=-37.5mm
\textheight=255mm
\textwidth=175mm
\or % 12 pt
\hoffset=-20mm
\voffset=-35mm
\textheight=245mm
\textwidth=175mm
\fi
\if@twocolumn
\hoffset=-14.3mm
\voffset=-38mm
\textheight=255mm
\textwidth=188mm
\fi
\fi
\if@twocolumn
\thelinewidth=0.47\textwidth
\else
\thelinewidth=\textwidth
\fi
% -- End of setup margins --
%---------- From package "lastpage" ------------------
\def\lastpage@putlabel{\addtocounter{page}{-1}%
\immediate\write\@auxout{\string\newlabel{LastPage}{{}{\thepage}}}%
\addtocounter{page}{1}}
\AtEndDocument{\clearpage\lastpage@putlabel}%
%---------- end of "lastpage" ------------------
% -- Setup sizes --
\newlength{\exmpwidinf}
\newlength{\exmpwidouf}
\newlength{\exmpwidewid}
\newlength{\exmpthreewidinf}
\newlength{\exmpthreewidouf}
\newlength{\exmpthreewidnote}
\newif\ifintentionallyblankpages
\exmpwidinf=0.43\thelinewidth
\exmpwidouf=0.43\thelinewidth
\exmpwidewid=0.9\thelinewidth
\exmpthreewidinf=0.28\thelinewidth
\exmpthreewidouf=0.28\thelinewidth
\exmpthreewidnote=0.30\thelinewidth
\newlength{\afterproblemhead}
\newlength{\afterconstraints}
\renewcommand{\t}[1]{\ifmmode{\mathtt{#1}}\else{\texttt{#1}}\fi}
\if@russian
\renewcommand{\le}{\leqslant}
\renewcommand{\ge}{\geqslant}
\renewcommand{\leq}{\leqslant}
\renewcommand{\geq}{\geqslant}
\else
\if@ukrainian
\renewcommand{\le}{\leqslant}
\renewcommand{\ge}{\geqslant}
\renewcommand{\leq}{\leqslant}
\renewcommand{\geq}{\geqslant}
\else
\parindent=0mm
\parskip=1ex
\fi
\fi
% -- End of setup sizes --
% -- Setup keywords --
\if@russian
\def\kw@ProblemTutorial{Разбор задачи}
\def\kw@Problem{Задача}
\def\kw@ProblemAuthor{Автор:}
\def\kw@ProblemDeveloper{Разработчик:}
\def\kw@ProblemOrigin{Источник:}
\def\kw@InputFileName{Имя входного файла:}
\def\kw@OutputFileName{Имя выходного файла:}
\def\kw@TimeLimit{Ограничение по времени:}
\def\kw@MemoryLimit{Ограничение по памяти:}
\def\kw@Feedback{Отображение результатов:}
\def\kw@stdin{стандартный поток ввода}
\def\kw@stdout{стандартный поток вывода}
\def\kw@Specification{Спецификация}
\def\kw@Interaction{Протокол взаимодействия}
\def\kw@Input{Формат входных данных}
\def\kw@Output{Формат выходных данных}
\def\kw@Example{Пример}
\def\kw@Examples{Примеры}
\def\kwExampleNotes{Пояснение}
\def\kw@Explanation{Пояснение к примеру}
\def\kw@Explanations{Пояснения к примерам}
\def\kw@Illustration{Иллюстрация}
\def\kw@Scoring{Система оценки}
\def\kw@Note{Замечание}
\def\kw@Notes{Замечания}
\def\kw@Constraints{Ограничения}
\def\kw@version{версия}
\def\kw@revision{ревизия}
\def\kw@SubtaskOne{Подзадача 1}
\def\kw@SubtaskTwo{Подзадача 2}
\def\kw@SubtaskThree{Подзадача 3}
\def\kw@SubtaskFour{Подзадача 4}
\def\kw@SubtaskFive{Подзадача 5}
\def\kw@SubtaskSix{Подзадача 6}
\def\kw@Subtask{Подзадача}
\def\kw@points{баллы}
\def\kw@Page{Страница}
\def\kw@of{из}
\def\kw@notstated{не указан}
\def\kw@IntentionallyBlankPage{Эта страница специально оставлена пустой}
\def\kw@defaultinputname{тест}
\def\kw@defaultoutputname{ответ}
\else
\if@ukrainian
\def\kw@ProblemTutorial{Розбір задачі}
\def\kw@Problem{Задача}
\def\kw@ProblemAuthor{Автор:}
\def\kw@ProblemDeveloper{Розробник:}
\def\kw@ProblemOrigin{Джерело:}
\def\kw@InputFileName{Назва вхідного файлу:}
\def\kw@OutputFileName{Назва вихідного файлу:}
\def\kw@TimeLimit{Ліміт часу:}
\def\kw@MemoryLimit{Ліміт використання пам'яті:}
\def\kw@Feedback{Відображення результатів:}
\def\kw@stdin{стандартний потік вводу}
\def\kw@stdout{стандартний потік виводу}
\def\kw@Specification{Специфікація}
\def\kw@Interaction{Протокол взаємодії}
\def\kw@Input{Формат вхідних даних}
\def\kw@Output{Формат вихідних даних}
\def\kw@Example{Приклад}
\def\kw@Examples{Приклади}
\def\kwExampleNotes{Пояснення}
\def\kw@Explanation{Пояснення до прикладу}
\def\kw@Explanations{Пояснения до прикладів}
\def\kw@Illustration{Ілюстрація}
\def\kw@Scoring{Система оцінювання}
\def\kw@Note{Зауваження}
\def\kw@Notes{Зауваження}
\def\kw@Constraints{Обмеження}
\def\kw@version{версія}
\def\kw@revision{ревізія}
\def\kw@SubtaskOne{Підзадача 1}
\def\kw@SubtaskTwo{Підзадача 2}
\def\kw@SubtaskThree{Підзадача 3}
\def\kw@SubtaskFour{Підзадача 4}
\def\kw@SubtaskFive{Підзадача 5}
\def\kw@SubtaskSix{Підзадача 6}
\def\kw@Subtask{Підзадача}
\def\kw@points{бали}
\def\kw@Page{Сторінка}
\def\kw@of{з}
\def\kw@notstated{не вказано}
\def\kw@IntentionallyBlankPage{Ця сторінка спеціально залишена порожньою}
\def\kw@defaultinputname{тест}
\def\kw@defaultoutputname{відповідь}
\else
\def\kw@ProblemTutorial{Problem Tutorial}
\def\kw@Problem{Problem}
\def\kw@ProblemAuthor{Author:}
\def\kw@ProblemDeveloper{Developer:}
\def\kw@ProblemOrigin{Origin:}
\def\kw@InputFileName{Input file:}
\def\kw@OutputFileName{Output file:}
\def\kw@TimeLimit{Time limit:}
\def\kw@MemoryLimit{Memory limit:}
\def\kw@Feedback{Feedback:}
\def\kw@stdin{standard input}
\def\kw@stdout{standard output}
\def\kw@Specification{Specification}
\def\kw@Interaction{Interaction Protocol}
\def\kw@Input{Input}
\def\kw@Output{Output}
\def\kw@Example{Example}
\def\kw@Examples{Examples}
\def\kwExampleNotes{Notes}
\def\kw@Explanation{Explanation}
\def\kw@Explanations{Explanations}
\def\kw@Illustration{Illustration}
\def\kw@Scoring{Scoring}
\def\kw@Note{Note}
\def\kw@Notes{Notes}
\def\kw@Constraints{Constraints}
\def\kw@version{version}
\def\kw@revision{revision}
\def\kw@SubtaskOne{Subtask 1}
\def\kw@SubtaskTwo{Subtask 2}
\def\kw@SubtaskThree{Subtask 3}
\def\kw@SubtaskFour{Subtask 4}
\def\kw@SubtaskFive{Subtask 5}
\def\kw@SubtaskSix{Subtask 6}
\def\kw@Subtask{Subtask}
\def\kw@points{points}
\def\kw@Page{Page}
\def\kw@of{of}
\def\kw@notstated{not stated}
\def\kw@IntentionallyBlankPage{This page is intentionally left blank}
\def\kw@defaultinputname{test}
\def\kw@defaultoutputname{answer}
\fi
\fi
\afterproblemhead=3mm
\afterconstraints=2mm
\newcommand{\problemheadfont}{\LARGE}
\newcommand{\problemsectionfont}{\Large}
\newcommand{\problemend}{
\clearpage
\ifintentionallyblankpages
\ifodd\value{page}
\else
\vspace*{\fill}
\begin{center}
\problemheadfont\kw@IntentionallyBlankPage
\end{center}
\vspace*{\fill}
\clearpage
\fi
\fi
}
\newcommand{\problemtextfont}{\normalsize}
\newcommand{\beforeproblemsectioncaption}{\smallbreak\smallskip}
\newcommand{\afterproblemsectioncaption}{\smallskip}
\if@twocolumn
\afterproblemhead=1mm
\afterconstraints=1mm
\renewcommand{\problemheadfont}{\large}
\renewcommand{\problemsectionfont}{\normalsize}
\renewcommand{\problemend}{\par\medskip}
\renewcommand{\problemtextfont}{\footnotesize}
\renewcommand{\beforeproblemsectioncaption}{\smallbreak\smallskip}
\renewcommand{\afterproblemsectioncaption}{}
\fi
% -- End of setup keywords --
% -- Problem sections --
\newcommand{\createsection}{\@newsection}
\def\@newsection#1#2{\DeclareRobustCommand{#1}{
{\beforeproblemsectioncaption\noindent\bf\problemsectionfont
\textsf{#2}}
\nopagebreak\par\afterproblemsectioncaption}
}
\newcommand{\createsectionexample}{\@newsectionexample}
\def\@newsectionexample#1#2{\DeclareRobustCommand{#1}{
\ifdefined\NoExamples\else%
{\beforeproblemsectioncaption\noindent\bf\problemsectionfont
\textsf{#2}}
\nopagebreak\par\afterproblemsectioncaption%
\fi%
}
}
\newcommand{\createsectionpar}{\@newsectionpar}
\def\@newsectionpar#1#2{\DeclareRobustCommand{#1}[1]{
{\beforeproblemsectioncaption\noindent\bf\problemsectionfont
\textsf{#2~##1}}
\nopagebreak\par\afterproblemsectioncaption}
}
\newcommand{\createsectionpartwo}{\@newsectionpartwo}
\def\@newsectionpartwo#1#2#3{\DeclareRobustCommand{#1}[2]{
{\beforeproblemsectioncaption\noindent\problemsectionfont
\textsf{\textbf{#2}~\textbf{##1}~(##2~#3)}}
\nopagebreak\par\afterproblemsectioncaption}
}
\createsection{\Specification}{\kw@Specification}
\createsection{\Interaction}{\kw@Interaction}
\createsection{\InputFile}{\kw@Input}
\createsection{\OutputFile}{\kw@Output}
\createsectionexample{\Example}{\kw@Example}
\createsectionexample{\Examples}{\kw@Examples}
\createsection{\Explanation}{\kw@Explanation}
\createsection{\Explanations}{\kw@Explanations}
\createsection{\Illustration}{\kw@Illustration}
\createsection{\Scoring}{\kw@Scoring}
\createsection{\Note}{\kw@Note}
\createsection{\Notes}{\kw@Notes}
\createsection{\Constraints}{\kw@Constraints}
\createsection{\SubtaskOne}{\kw@SubtaskOne}
\createsection{\SubtaskTwo}{\kw@SubtaskTwo}
\createsection{\SubtaskThree}{\kw@SubtaskThree}
\createsection{\SubtaskFour}{\kw@SubtaskFour}
\createsection{\SubtaskFive}{\kw@SubtaskFive}
\createsection{\SubtaskSix}{\kw@SubtaskSix}
\createsectionpar{\Subtask}{\kw@Subtask}
\createsectionpartwo{\SubtaskWithCost}{\kw@Subtask}{\kw@points}
% -- End of problem sections
% -- Default limits definition --
\if@russian
\def\defaulttimelimit{2 секунды}
\else
\if@ukrainian
\def\defaulttimelimit{2 секунди}
\else
\def\defaulttimelimit{2 seconds}
\fi
\fi
\if@russian
\def\defaultmemorylimit{256 мебибайт}
\else
\if@ukrainian
\def\defaulttimelimit{256 мебібайт}
\else
\def\defaultmemorylimit{256 mebibytes}
\fi
\fi
% -- End of default limits definition --
% -- Problem environment --
\def\defaultproblemauthor{\textit{\kw@notstated}}
\gdef\thisproblemauthor{\defaultproblemauthor}
\def\defaultproblemdeveloper{\textit{\kw@notstated}}
\gdef\thisproblemdeveloper{\defaultproblemdeveloper}
\def\defaultproblemorigin{\textit{\kw@notstated}}
\gdef\thisproblemorigin{\defaultproblemorigin}
\newif\ifdisplayauthor
\newif\ifdisplaydeveloper
\newif\ifdisplayorigin
\newif\ifrevisionsignature
\newif\ifdisplayauthorinfooter
\newif\ifdisplaydeveloperinfooter
\newcounter{problem}
\newcounter{subtasknum}[problem]
\newcommand{\SubtaskWithScore}[1]{%
{\addtocounter{subtasknum}{1}%
\beforeproblemsectioncaption\noindent\problemsectionfont%
\textsf{\textbf{\kw@Subtask~\arabic{subtasknum}}}%
\textsf{~(\kw@points:~#1)}%
\nopagebreak\par\afterproblemsectioncaption}%
}%
\newenvironment{tutorial}[1]{%
\bigskip%
\noindent%
\refstepcounter{problem}
\textbf{\problemheadfont\textsf{\ifdefined\ShortProblemTitle\ifdefined\ProblemIndex\ProblemIndex. \fi\else\kw@Problem\ \ifdefined\ProblemIndex\ProblemIndex\else\if@arabic\arabic{problem}\else\Alph{problem}\fi\fi. \fi #1}}%
\nopagebreak%
\problemtextfont%
}
\newenvironment{@problem}[6]{
\global\let\lastproblemauthor\thisproblemauthor
\global\let\lastproblemdeveloper\thisproblemdeveloper
\global\let\lastproblemorigin\thisproblemorigin
% Hotfix
%\def\@memorylimit{#5}
%% -- Default memory limit --
%% :FIXME:
%\def\@t{#5}
%
%\ifx\@t\empty
% \def\@memorylimit{\defaultmemorylimit}
%\else
%%\ifcat\par\@t
%% \def\@memorylimit{\defaultmemorylimit}
%%\else
% \def\@memorylimit{#5}
%%\fi
%\fi
%% -- End of default memory limit --
% -- No feedback case --
% :FIXME:
\def\@t{#6}
\ifx\@t\empty
\def\@feedback{}
\else
%\ifcat\par\@t
% \def\@feedback{}
%\else
\def\@feedback{\kw@Feedback & #6 \\}
\fi
%\fi
% -- End of no feedback case --
{
\ifdefined\NoProblemHead\else%
\noindent
\refstepcounter{problem}
\textbf{\problemheadfont\textsf{%
\ifdefined\ShortProblemTitle\ifdefined\ProblemIndex\ProblemIndex. \fi\else\kw@Problem\ \ifdefined\ProblemIndex\ProblemIndex\else\if@arabic\arabic{problem}\else\Alph{problem}\fi\fi. \fi%
#1%
\ifdefined\DivisionNumber%
\if\DivisionNumber2%
{\ \textit{(Division\ \DivisionNumber)}}%
\fi%
\fi%
}}%
\nopagebreak%
\par\vspace{\afterproblemhead}%
\problemtextfont\parindent=6.5mm%
\vbox{
\begin{tabular}{l@{\extracolsep{1cm}}l}
\ifdisplayauthor%
\kw@ProblemAuthor & \thisproblemauthor \\
\fi%
\ifdisplaydeveloper%
\kw@ProblemDeveloper & \thisproblemdeveloper \\
\fi%
\ifdisplayorigin%
\kw@ProblemOrigin & \thisproblemorigin \\
\fi%
\ifdefined\NoInputFileName\else%
\ifx&#2&%
\else%
\kw@InputFileName & \texttt{#2} \\
\fi\fi%
\ifdefined\NoOutputFileName\else%
\ifx&#3&%
\else%
\kw@OutputFileName & \texttt{#3} \\
\fi\fi%
\ifdefined\NoTimeLimit\else%
\ifx&#4&%
\else%
\kw@TimeLimit & #4 \\
\fi\fi%
\ifdefined\NoMemoryLimit\else%
\ifx&#5&%
\else%
\kw@MemoryLimit & #5 \\
\fi\fi%
% \kw@MemoryLimit & \@memorylimit \\
\@feedback
\end{tabular}
}
\nopagebreak
\par\vspace{\afterconstraints}
\fi%
}
\problemtextfont
\newcommand{\InputFileName}{\ifx\relax#2\relax{\kw@defaultinputname}\else{#2}\fi}
\newcommand{\OutputFileName}{\ifx\relax#3\relax{\kw@defaultoutputname}\else{#3}\fi}
}{%
\global\let\lastproblemauthor\thisproblemauthor%
\global\let\lastproblemdeveloper\thisproblemdeveloper%
\global\let\lastproblemdorigin\thisproblemorigin%
\gdef\thisproblemauthor{\defaultproblemauthor}%
\gdef\thisproblemdeveloper{\defaultproblemdeveloper}%
\gdef\thisproblemorigin{\defaultproblemorigin}%
\problemend%
}
\def\s@tm@cr@s{
\def\widthin##1{\exmpwidinf=##1\relax}
\def\widthout##1{\exmpwidouf=##1\relax}
\def\stretchin##1{\advance\exmpwidinf by ##1\relax}
\def\stretchout##1{\advance\exmpwidouf by ##1\relax}
\@ifstar{
\error Star must not be used in example environment any more
}
}
% This is magic, which delete space after verbatiminput
\addto@hook{\every@verbatim}{\topsep=0pt\relax}
% :FIXME:
\newenvironment{example}[1][]{
\s@tm@cr@s#1
\ttfamily\obeylines\obeyspaces\frenchspacing
\newcommand{\exmp}[2]{
\ifdefined\NoExamples\else%
\begin{minipage}[t]{\exmpwidinf}\rightskip=0pt plus 1fill\relax##1\medskip\end{minipage}&
\begin{minipage}[t]{\exmpwidouf}\rightskip=0pt plus 1fill\relax##2\medskip\end{minipage}\\
\hline
\fi%
}
\newcommand{\exmpfile}[2]{
\ifdefined\NoExamples\else%
\exmp{
\verbatiminput{##1}
}{
\verbatiminput{##2}
}%
\fi%
}
\ifdefined\NoExamples\else%
\begin{tabular}{|l|l|}
\hline
\multicolumn{1}{|c|}{\bf\texttt{\InputFileName}}&
\multicolumn{1}{c|}{\bf\texttt{\OutputFileName}}\\
\hline
\fi%
}{
\ifdefined\NoExamples\else%
\end{tabular}
\fi%
}
\newenvironment{examplewide}[1][]{%
\s@tm@cr@s#1
\ttfamily\obeylines\obeyspaces\frenchspacing
\newcommand{\exmp}[2]{
\ifdefined\NoExamples\else%
\begin{tabular}{|c|}
\hline
\multicolumn{1}{|c|}{\bf\texttt{\InputFileName}}\\
\hline
\begin{minipage}[t]{\exmpwidewid}\rightskip=0pt plus 1fill\relax
##1
\medskip\end{minipage}\\
\hline
\multicolumn{1}{|c|}{\bf\texttt{\OutputFileName}}\\%
\hline
\begin{minipage}[t]{\exmpwidewid}\rightskip=0pt plus 1fill\relax
##2
\medskip\end{minipage}\\%
\hline
\end{tabular}
\fi%
}
\newcommand{\exmpfile}[2]{
\ifdefined\NoExamples\else%
\exmp{
\verbatiminput{##1}
}{
\verbatiminput{##2}
}%
\fi%
}
}{
}
\newenvironment{examplethree}[1][]{
\s@tm@cr@s#1
\ttfamily\obeylines\obeyspaces\frenchspacing
\newcommand{\exmp}[3]{
\ifdefined\NoExamples\else%
\begin{minipage}[t]{\exmpthreewidinf}\rightskip=0pt plus 1fill\relax##1\medskip\end{minipage}&
\begin{minipage}[t]{\exmpthreewidouf}\rightskip=0pt plus 1fill\relax##2\medskip\end{minipage}&
\begin{minipage}[t]{\exmpthreewidnote}\rightskip=0pt plus 1fill\relax##3\medskip\end{minipage}\\
\hline
\fi%
}
\newcommand{\exmpfile}[3]{
\ifdefined\NoExamples\else%
\exmp{
\verbatiminput{##1}
}{
\verbatiminput{##2}
}{
##3
}%
\fi%
}
\ifdefined\NoExamples\else%
\begin{tabular}{|l|l|l|}
\hline
\multicolumn{1}{|c|}{\bf\texttt{\InputFileName}}&
\multicolumn{1}{|c|}{\bf\texttt{\OutputFileName}}&
\multicolumn{1}{|c|}{\bf\texttt{\expandafter\unexpanded{\expandafter\kwExampleNotes}}}\\
\hline
\fi%
}{
\ifdefined\NoExamples\else%
\end{tabular}
\fi%
}
% -- This is hack to make feedback argument optional
\newenvironment{problem}[5]{%
\def\@ProblemCommon{\begin{@problem}{#1}{#2}{#3}{#4}{#5}}%
\newcommand\@problemSix[1]{\@ProblemCommon{##1}}%
\newcommand\@problemFive{\@ProblemCommon{}}%
\@ifnextchar\bgroup\@problemSix\@problemFive%
}{%
\end{@problem}%
}
% -- End of problem environment --
% -- Declare "shortitems" and "shortnums" environment: it's a "compact itemize" --
\if@twocolumn
\def\shortitems{\vspace{-1mmplus6mm}\itemize\itemsep-0.618mmplus0.5mm\relax}%
\def\endshortitems{\vspace{-1mmplus6mm}\enditemize}%
\def\shortnums{\vspace{-1mmplus6mm}\enumerate\itemsep-0.618mmplus0.5mm\relax}%
\def\endshortnums{\vspace{-1mmplus6mm}\endenumerate}%
\else
\def\shortitems{\vspace{-3mmplus2mm}\itemize\itemsep-1.618mmplus0.5mm\relax}%
\def\endshortitems{\vspace{-3mmplus2mm}\enditemize}%
\def\shortnums{\vspace{-3mmplus2mm}\enumerate\itemsep-1.618mmplus0.5mm\relax}%
\def\endshortnums{\vspace{-3mmplus2mm}\endenumerate}%
\fi
% -- end of "shortitems" and "shortnums" declaration --
\newcommand{\thecontestname}{Olympiad in Informatics}
\newcommand{\thecontestlocation}{Somewhere}
\newcommand{\thecontestdate}{Once upon a time}
\newcommand{\therevision}{undefined}
\DeclareRobustCommand{\contestname}{\thecontestname\par\thecontestlocation\unskip, \thecontestdate}
\DeclareRobustCommand{\contest}[3]{
\renewcommand{\thecontestname}{#1}
\renewcommand{\thecontestlocation}{#2}
\renewcommand{\thecontestdate}{#3}
\def\temp{#1}\ifx\temp\empty
\def\temp{#2}\ifx\temp\empty
\def\temp{#3}\ifx\temp\empty
\let\thecontestname\undefined%
\let\thecontestlocation\undefined%
\let\thecontestdate\undefined%
\fi
\fi
\fi
}
\DeclareRobustCommand{\revision}[1]{
\renewcommand{\therevision}{#1}
}
\makeatletter
\renewcommand{\@oddhead}{
\ifdefined\thecontestname
\parbox{\textwidth}{
\sffamily
\begin{center}
\protect\contestname
\\[2pt]
\hrule
\end{center}
}
\fi
}
\renewcommand{\@oddfoot}{
\gdef\problemletter{\if@arabic\arabic{problem}\else\Alph{problem}\fi}
% Revision signature
\ifrevisionsignature%
%\if@revsign%
{\gdef\rsigfooter{, \kw@revision\ \therevision}}%
\else%
{\gdef\rsigfooter{}}%
\fi%
\ifdisplayauthorinfooter%
%\if@newfooter%
{\gdef\thefooter%
{~\quad{\kw@Problem\ \problemletter%
\ifdefined\DivisionNumber{ (Div.~\DivisionNumber)}\fi}%
{\hfill}%
{\kw@ProblemAuthor~\lastproblemauthor}%
{\hfill}%
{\kw@Page\ \thepage\ \kw@of\ \pageref{LastPage}\rsigfooter}\quad~}}%
\else%
\ifdisplaydeveloperinfooter%
{\gdef\thefooter%
{~\quad{\kw@Problem\ \problemletter}%
{\hfill}%
{\kw@ProblemDeveloper~\lastproblemdeveloper}%
{\hfill}%
{\kw@Page\ \thepage\ \kw@of\ \pageref{LastPage}\rsigfooter}\quad~}}%
\else%
{\gdef\thefooter%
{{\hfil}\kw@Page\ \thepage\ \kw@of\ \pageref{LastPage}\rsigfooter\hfil}}%
\fi%
\fi%
\parbox{\textwidth}{
\hrule
\vspace{6pt}
\sffamily
\thefooter
}
}
\makeatother
\headheight=2cm
\headsep=6mm
\hfuzz=0.5pt
\sloppy

View File

@@ -0,0 +1,86 @@
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#include "testlib.h"
using namespace std;
int main(int argc, char* argv[]) {
registerGen(argc, argv, 1);
int t = opt<int>(1);
vector<int> a;
vector<vector<int>> b;
if (t == 1) {
a.push_back(1);
b.push_back({ 1, 2, 1 });
}
if (t == 2) {
a.push_back(1);
for (int i = 0; i < 100000; i += 2) {
b.push_back({ 1, 2, 1 });
b.push_back({ 3, 2 });
}
}
if (t == 3) {
a.push_back(1e9);
for (int i = 0; i < 50000; i++)
b.push_back({ 2, i + 1 });
for (int i = 0; i < 50000; i++)
b.push_back({ 3, i + 1 });
}
if (t == 4) {
for (int i = 0; i < 100000; i++)
a.push_back(i + 1);
for (int i = 0; i < 100000; i++)
b.push_back({ 3, i + 1 });
}
if (t == 5) {
for (int i = 0; i < 100000; i++)
a.push_back(i + 1);
for (int i = 0; i < 100000; i++)
b.push_back({ 1, 100000 + i + 1, i + 1 });
}
if (t == 6) {
for (int i = 0; i < 100000; i++)
a.push_back(1e9 - i);
for (int i = 0; i < 50000; i++) {
b.push_back({ 1, i + 1, (int)1e9 - i });
b.push_back({ 3, (int)1e9 - i });
}
}
if (t == 7) {
for (int i = 0; i < 100000; i++)
a.push_back(1e9 - i);
for (int i = 0; i < 100000; i++)
b.push_back({ 3, (int)1e9 - i });
}
if (t == 8) {
for (int i = 0; i < 100000 && b.size() < 100000; i++)
a.push_back(i + 1);
for (int i = 0; i < 100000 && b.size() < 100000; i++)
b.push_back({ 3, (int)1e5 - i });
}
if (t == 9) {
for (int i = 0; i < 100000; i++)
a.push_back(i + 1);
for (int i = 0; i < 100000 && b.size() < 100000; i += 2)
b.push_back({ 3, i + 1 });
for (int i = 0; i < 100000 && b.size() < 100000; i += 2)
b.push_back({ 2, i + 1 });
}
if (t == 10) {
for (int i = 100000; i > 0; i--)
a.push_back(i);
for (int i = 0; i < 100000 && b.size() < 100000; i += 2)
b.push_back({ 3, i + 1 });
for (int i = 0; i < 100000 && b.size() < 100000; i += 2)
b.push_back({ 2, i + 1 });
}
cout << a.size() << ' ' << b.size() << '\n';
for (int i = 0; i < a.size(); i++)
cout << a[i] << " \n"[i + 1 == a.size()];
for (auto i : b) {
for (int j = 0; j < i.size(); j++)
cout << i[j] << " \n"[j + 1 == i.size()];
}
}

Binary file not shown.

View File

@@ -0,0 +1,79 @@
\begin{problem}{${problem.name}}<#--
-->{<#if "stdin" == problem.inputFile><#--
--><#if "russian" == language>стандартный ввод<#--
--><#else>standard input<#--
--></#if><#else>${problem.inputFile}</#if>}<#--
-->{<#if "stdout" == problem.outputFile><#--
--><#if "russian" == language>стандартный вывод<#--
--><#else>standard output<#--
--></#if><#else>${problem.outputFile}</#if>}<#--
--><#assign timeLimit=problem.timeLimit/1000/><#--
--><#if language="russian"><#--
--><#if problem.timeLimit%1000!=0||(10<=timeLimit%100&&timeLimit%100<20)||timeLimit%10=0||5<=timeLimit><#--
-->{${timeLimit?c} секунд}<#--
--><#else><#--
--><#if timeLimit%10=1><#--
-->{${timeLimit?c} секунда}<#--
--><#else><#--
-->{${timeLimit?c} секунды}<#--
--></#if><#--
--></#if><#--
--><#else><#--
-->{${timeLimit?c} second<#if (timeLimit!=1)>s</#if>}<#--
--></#if><#--
--><#assign memoryLimit=problem.memoryLimit/1048576/><#--
--><#if language="russian"><#--
--><#if problem.memoryLimit%1048576==0&&!(10<=memoryLimit%100&&memoryLimit%100<20)&&2<=memoryLimit%10&&memoryLimit%10<5><#--
-->{${memoryLimit?c} мегабайта}
<#else><#--
-->{${memoryLimit?c} мегабайт}
</#if>
<#else><#--
-->{${memoryLimit?c} megabyte<#if (memoryLimit>1)>s</#if>}
</#if>
<#if providedStatementsCommands?? && providedStatementsCommands?size != 0><#--
--><#list providedStatementsCommands as command><#--
-->${command?string}
</#list>
</#if>
${problem.legend}
<#if problem.input?? && (problem.input?length>0)>
\InputFile
${problem.input}
</#if>
<#if problem.output?? && (problem.output?length>0)>
\OutputFile
${problem.output}
</#if>
<#if problem.interaction?? && (problem.interaction?length>0)>
\Interaction
${problem.interaction}
</#if>
<#if problem.scoring?? && (problem.scoring?length>0)>
\Scoring
${problem.scoring}
</#if>
<#if (problem.sampleTests?size>0)>
\Example<#if (problem.sampleTests?size>1)>s</#if>
\begin{example}
<#list problem.sampleTests as test>
\exmpfile{${test.inputFile}}{${test.outputFile}}%
</#list>
\end{example}
</#if>
<#if (problem.notes??) && (problem.notes?length > 0)>
\Note
${problem.notes}
</#if>
\end{problem}

View File

@@ -0,0 +1,53 @@
\documentclass [11pt, a4paper, oneside] {article}
\usepackage [T2A] {fontenc}
\usepackage [utf8] {inputenc}
\usepackage [english, russian] {babel}
\usepackage {amsmath}
\usepackage {amssymb}
\usepackage <#if contest.language?? && contest.language="russian">[russian]<#elseif contest.language?? && contest.language="ukrainian">[ukrainian]</#if>{olymp}
\usepackage {comment}
\usepackage {epigraph}
\usepackage {expdlist}
\usepackage {graphicx}
\usepackage {multirow}
\usepackage {siunitx}
\usepackage {ulem}
%\usepackage {hyperref}
\usepackage {import}
\usepackage {ifpdf}
\usepackage {xparse}
\ifpdf
\DeclareGraphicsRule{*}{mps}{*}{}
\fi
\begin {document}
\contest
{${contest.name!}}%
{${contest.location!}}%
{${contest.date!}}%
\binoppenalty=10000
\relpenalty=10000
\renewcommand{\t}{\texttt}
\renewcommand{\thefootnote}{\fnsymbol{footnote}}
<#if shortProblemTitle?? && shortProblemTitle>
\def\ShortProblemTitle{}
</#if>
<#list statements as statement>
<#if statement.path??>
\graphicspath{{${statement.path}}}
<#if statement.index??>
\def\ProblemIndex{${statement.index}}
</#if>
\import{${statement.path}}{./${statement.file}}
<#else>
\input ${statement.file}
</#if>
</#list>
\end {document}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
7 6
1 2 3 4 5 6 7
1 8 3
2 9
3 3
1 3 9
2 10
3 1

View File

@@ -0,0 +1,3 @@
1 1
1
1 1 1

View File

@@ -0,0 +1,3 @@
1 1
1
2 1

View File

@@ -0,0 +1,4 @@
2 2
1 2
1 3 2
3 4

Binary file not shown.

View File

@@ -0,0 +1,11 @@
\begin{tutorial}{${problem.name}}
<#if providedTutorialCommands?? && providedTutorialCommands?size != 0><#--
--><#list providedTutorialCommands as command><#--
-->${command?string}
</#list>
</#if>
${problem.tutorial}
\end{tutorial}

View File

@@ -0,0 +1,52 @@
#include <bits/stdc++.h>
#include "testlib.h"
using namespace std;
int minN = 1, maxN = 1e5;
int minM = 1, maxM = 1e5;
int minA = 1, maxA = 1e9;
int main(int argc, char* argv[]) {
registerValidation(argc, argv);
int n = inf.readInt(minN, maxN, "n");
inf.readSpace();
int m = inf.readInt(minM, maxM, "m");
inf.readEoln();
set<int> st;
for (int i = 0; i < n; i++) {
int a = inf.readInt(minA, maxA, "a");
if (i == n - 1)
inf.readEoln();
else
inf.readSpace();
st.insert(a);
}
inf.ensuref((int)st.size() == n, "a is unique");
for (int i = 0; i < m; i++) {
int t = inf.readInt(1, 3, "t");
inf.readSpace();
if (t == 1) {
int x = inf.readInt(minA, maxA, "x");
inf.readSpace();
int y = inf.readInt(minA, maxA, "y");
inf.ensuref(st.count(x) == 0, "x is already in list");
inf.ensuref(st.count(y) == 1, "y is not in list");
st.insert(x);
inf.readEoln();
}
if (t == 2) {
int x = inf.readInt(minA, maxA, "x");
inf.ensuref(st.count(x) == 0, "xx is already in list");
st.insert(x);
inf.readEoln();
}
if (t == 3) {
int x = inf.readInt(minA, maxA, "x");
inf.ensuref(st.count(x) == 1, "x is not in list");
st.erase(x);
inf.readEoln();
}
}
inf.readEof();
}

BIN
exam-queue-17/files/val.exe Normal file

Binary file not shown.

168
exam-queue-17/problem.xml Normal file
View File

@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<problem revision="17" short-name="exam-queue" url="https://polygon.codeforces.com/p6Un8qn/valavshonok/exam-queue">
<names>
<name language="russian" value="Очередь за кексами"/>
</names>
<statements>
<statement charset="UTF-8" language="russian" mathjax="true" path="statements/russian/problem.tex" type="application/x-tex"/>
<statement charset="UTF-8" language="russian" mathjax="true" path="statements/.html/russian/problem.html" type="text/html"/>
<statement language="russian" path="statements/.pdf/russian/problem.pdf" type="application/pdf"/>
</statements>
<tutorials>
<tutorial charset="UTF-8" language="russian" mathjax="true" path="statements/russian/tutorial.tex" type="application/x-tex"/>
<tutorial charset="UTF-8" language="russian" mathjax="true" path="statements/.html/russian/tutorial.html" type="text/html"/>
<tutorial language="russian" path="statements/.pdf/russian/tutorial.pdf" type="application/pdf"/>
</tutorials>
<judging cpu-name="Intel(R) Core(TM) i3-8100 CPU @ 3.60GHz" cpu-speed="3600" input-file="" output-file="" run-count="1">
<testset name="tests">
<time-limit>1000</time-limit>
<memory-limit>268435456</memory-limit>
<test-count>51</test-count>
<input-path-pattern>tests/%02d</input-path-pattern>
<answer-path-pattern>tests/%02d.a</answer-path-pattern>
<tests>
<test group="SAMPLES" method="manual" points="0.0" sample="true"/>
<test cmd="gen 1 5 10 5 10 1 100" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 2 5 10 5 10 1 100" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 3 5 10 5 10 1 100" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 4 5 10 5 10 1 100" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 5 5 10 5 10 1 100" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 1 50 100 500 1000 1 1000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 2 50 100 500 1000 1 1000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 3 50 100 500 1000 1 1000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 4 50 100 500 1000 1 1000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 5 50 100 500 1000 1 1000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 1 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 2 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 3 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 4 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 5 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 6 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 7 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 8 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 9 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 10 50000 100000 50000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 1 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 2 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 3 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 4 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 5 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 6 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 7 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 8 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 9 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen 10 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen1 1 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen1 2 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen1 3 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen1 4 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen1 5 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen2 1 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen2 2 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen2 3 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen2 4 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="gen2 5 100000 100000 100000 100000 1 1000000000" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 1" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 2" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 3" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 4" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 5" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 6" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 7" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 8" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 9" group="POINTS" method="generated" points="2.0"/>
<test cmd="print 10" group="POINTS" method="generated" points="2.0"/>
</tests>
<groups>
<group feedback-policy="points" name="POINTS" points-policy="each-test">
<dependencies>
<dependency group="SAMPLES"/>
</dependencies>
</group>
<group feedback-policy="points" name="SAMPLES" points="0.0" points-policy="complete-group"/>
</groups>
</testset>
</judging>
<files>
<resources>
<file path="files/olymp.sty"/>
<file path="files/problem.tex"/>
<file path="files/statements.ftl"/>
<file path="files/testlib.h" type="h.g++"/>
<file path="files/tutorial.tex"/>
</resources>
<executables>
<executable>
<source path="files/gen.cpp" type="cpp.gcc14-64-msys2-g++23"/>
<binary path="files/gen.exe" type="exe.win32"/>
</executable>
<executable>
<source path="files/gen1.cpp" type="cpp.gcc14-64-msys2-g++23"/>
<binary path="files/gen1.exe" type="exe.win32"/>
</executable>
<executable>
<source path="files/gen2.cpp" type="cpp.gcc14-64-msys2-g++23"/>
<binary path="files/gen2.exe" type="exe.win32"/>
</executable>
<executable>
<source path="files/print.cpp" type="cpp.gcc14-64-msys2-g++23"/>
<binary path="files/print.exe" type="exe.win32"/>
</executable>
<executable>
<source path="files/val.cpp" type="cpp.gcc14-64-msys2-g++23"/>
<binary path="files/val.exe" type="exe.win32"/>
</executable>
</executables>
</files>
<assets>
<checker name="std::ncmp.cpp" type="testlib">
<source path="files/check.cpp" type="cpp.g++17"/>
<binary path="check.exe" type="exe.win32"/>
<copy path="check.cpp"/>
<testset>
<test-count>0</test-count>
<input-path-pattern>files/tests/checker-tests/%02d</input-path-pattern>
<output-path-pattern>files/tests/checker-tests/%02d.o</output-path-pattern>
<answer-path-pattern>files/tests/checker-tests/%02d.a</answer-path-pattern>
<tests/>
</testset>
</checker>
<validators>
<validator>
<source path="files/val.cpp" type="cpp.gcc14-64-msys2-g++23"/>
<binary path="files/val.exe" type="exe.win32"/>
<testset>
<test-count>4</test-count>
<input-path-pattern>files/tests/validator-tests/%02d</input-path-pattern>
<tests>
<test verdict="valid"/>
<test verdict="invalid"/>
<test verdict="invalid"/>
<test verdict="invalid"/>
</tests>
</testset>
</validator>
</validators>
<solutions>
<solution tag="accepted">
<source path="solutions/nyatl_ok.cpp" type="cpp.gcc14-64-msys2-g++23"/>
<binary path="solutions/nyatl_ok.exe" type="exe.win32"/>
</solution>
<solution tag="main">
<source path="solutions/valavshonok_OK.cpp" type="cpp.gcc14-64-msys2-g++23"/>
<binary path="solutions/valavshonok_OK.exe" type="exe.win32"/>
</solution>
</solutions>
</assets>
<properties>
<property name="tests-wellformed" value="true"/>
</properties>
<stresses>
<stress-count>0</stress-count>
<stress-path-pattern>stresses/%03d</stress-path-pattern>
<list/>
</stresses>
<tags>
<tag value="realization"/>
</tags>
</problem>

View File

@@ -0,0 +1,19 @@
set argumentCount=0
for %%x in (%*) do Set /A argumentCount+=1
if not "%argumentCount%"=="4" pause 0
if "%1"=="" pause 0
if "%2"=="" pause 0
if not exist %1 pause 0
files\val.exe --testset "%~3" --group "%~4" < %1
if errorlevel 1 pause 0
solutions\valavshonok_OK.exe < %1 > output.txt
if errorlevel 1 pause 0
if not exist output.txt pause 0
move output.txt %2
check.exe %1 %2 %2
:start
set error=1
if %errorlevel% equ 0 set error=0
if %errorlevel% equ 7 set error=0
if %error% equ 1 pause 0
:end

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
if [ "$#" -ne "4" ]; then
read
fi
if [ "$1" = "" ]; then
read
fi
if [ "$2" = "" ]; then
read
fi
if [ ! -f "$1" ]; then
read
fi
echo "Running validator"
wine files/towin.exe "$1" | wine files/val.exe --testset "$3" --group "$4"
if [ "$?" -ne "0" ]; then
read
fi
echo "Running solution valavshonok_OK.cpp"
wine solutions/valavshonok_OK.exe < "$1" > output.txt
if [ "$?" -ne "0" ]; then
echo "Solution returned non-zero exit code"
read
fi
if [ ! -f "output.txt" ]; then
echo "Solution didn't produced output"
read
fi
mv output.txt "$2"
echo "Running checker"
wine check.exe "$1" "$2" "$2"
if [ "$?" -ne "0" ] && [ "$?" -ne "7" ]; then
echo "Checker exit code is not equal to 0 and 7"
read
fi

View File

@@ -0,0 +1,22 @@
rem parameter 1 is generator execution command line from the root of the package
rem parameter 2 is test input file path from the root of the package
rem parameter 3 is the test index
if "%~1"=="" pause 0
if "%~2"=="" pause 0
if "%~3"=="" pause 0
del /F /Q "%~2"
if exist tmp-for-generator-execution rd /S /Q tmp-for-generator-execution
md tmp-for-generator-execution
cd tmp-for-generator-execution
%~1
if errorlevel 1 pause 0
if exist "%~3" copy "%~3" "..\%~2"
cd ..
rd /S /Q tmp-for-generator-execution
if not exist "%~2" pause 0

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env bash
if [ "$1" = "" ]
then
echo "First parameter is empty"
read
fi
if [ "$2" = "" ]
then
echo "Second parameter is empty"
read
fi
if [ "$3" = "" ]
then
echo "Third parameter is empty"
read
fi
rm -f "$2"
rm -rf tmp-for-input-generation
mkdir tmp-for-input-generation
cd tmp-for-input-generation
eval $1
if [ "$?" -ne "0" ]
then
echo "Executed "../"$1"", but it returns non-zero exit code"
read
fi
cp "$3" "../$2"
if [ "$?" -ne "0" ]
then
echo "Can't copy $3 to ../$2"
read
fi
if [ ! -f "../$2" ]
then
echo "Can't find ../$2"
read
fi
cd ..
rm -rf tmp-for-input-generation

View File

@@ -0,0 +1,70 @@
@echo off
rem parameter 1 is generator execution command line from the root of the package
rem parameter 2 is test input file path from the root of the package or several paths separated with ":"
rem parameter 3 is the test index or several indices separated with ":"
if "%~1"=="" pause 0
if "%~2"=="" pause 0
if "%~3"=="" pause 0
if exist tmp-for-generator-execution rd /S /Q tmp-for-generator-execution
md tmp-for-generator-execution
cd tmp-for-generator-execution
%~1
if errorlevel 1 pause 0
setlocal ENABLEDELAYEDEXPANSION
set paths=%~2
set indices=%~3
:tokenLoop
if "!paths!" EQU "" goto splitEnd
if "!indices!" EQU "" goto splitEnd
for /f "delims=:" %%a in ("!paths!") do set pathItem=%%a
for /f "delims=:" %%a in ("!indices!") do set indexItem=%%a
if exist "..\!pathItem!" del /F /Q "..\!pathItem!"
set copied=0
if exist "!indexItem!" (
set copied=1
copy "!indexItem!" "..\!pathItem!" > nul
)
if exist "0!indexItem!" (
set copied=1
copy "0!indexItem!" "..\!pathItem!" > nul
)
if exist "00!indexItem!" (
set copied=1
copy "00!indexItem!" "..\!pathItem!" > nul
)
echo %copied%
if "%copied%"=="0" (
echo Unable to find test !indexItem!
pause 0
)
echo Test #!indexItem! has been generated and copied to !pathItem!
:pathsStripLoop
set pathsFirstChar=!paths:~0,1!
set paths=!paths:~1!
if "!paths!" EQU "" goto splitEnd
if "!pathsFirstChar!" NEQ ":" goto pathsStripLoop
:indicesStripLoop
set indicesFirstChar=!indices:~0,1!
set indices=!indices:~1!
if "!indices!" EQU "" goto splitEnd
if "!indicesFirstChar!" NEQ ":" goto indicesStripLoop
goto tokenLoop
:splitEnd
endlocal
cd ..
rd /S /Q tmp-for-generator-execution

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# parameter 1 is generator execution command line from the root of the package
# parameter 2 is test input file path from the root of the package or several paths separated with ":"
# parameter 3 is the test index or several indices separated with ":"
if [ "$1" = "" ]
then
echo "First parameter is empty"
read
fi
if [ "$2" = "" ]
then
echo "Second parameter is empty"
read
fi
if [ "$3" = "" ]
then
echo "Third parameter is empty"
read
fi
rm -rf tmp-for-input-generation
mkdir tmp-for-input-generation
cd tmp-for-input-generation
eval "$1"
if [ "$?" -ne "0" ]
then
echo "Executed "../"$1"", but it returns non-zero exit code"
read
fi
paths=($(echo "$2" | tr ":" "\n"))
indices=($(echo "$3" | tr ":" "\n"))
for (( i = 0 ; i < ${#paths[@]} ; i++ ))
do
rm -f "../${paths[$i]}"
cp "${indices[$i]}" "../${paths[$i]}" 2> /dev/null ||
cp "0${indices[$i]}" "../${paths[$i]}" 2> /dev/null ||
cp "00${indices[$i]}" "../${paths[$i]}" 2> /dev/null
if [ "$?" -ne "0" ]
then
echo "Can't copy ${indices[$i]} to ../${paths[$i]}"
read
fi
if [ ! -f "../${paths[$i]}" ]
then
echo "Can't find ../${paths[$i]}"
read
fi
echo "Test #${indices[$i]} has been generated and copied to ${paths[$i]}"
done
cd ..
rm -rf tmp-for-input-generation

View File

@@ -0,0 +1,10 @@
rem %1 is generator execution command line from the root of the package
rem %2 is test input file path from the root of the package
rem %3 is the test index
if "%~1"=="" pause 0
if "%~2"=="" pause 0
del /F /Q "%~2"
%~1 > "%~2"
if errorlevel 1 pause 0
if not exist "%~2" pause 0

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
if [ "$1" = "" ]
then
echo "First parameter is empty"
read
fi
if [ "$2" = "" ]
then
echo "Second parameter is empty"
read
fi
rm -f "$2"
eval $1 > $2
if [ "$?" -ne "0" ]
then
echo "Executed $1, but it returns non-zero exit code"
read
fi
if [ ! -f "$2" ]
then
echo "Executed ""$1" > "$2"", but it didn't create file"
read
fi

View File

@@ -0,0 +1,4 @@
echo Running 0 checker test(s)
echo Running 0 checker test(s) 1> checker-tests.log
del /F /Q checker-tests.log
echo Checker test(s) finished

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
echo "Running 0 checker test(s)"
echo "Running 0 checker test(s)" 1> checker-tests.log
rm -f checker-tests.log
echo "Checker test(s) finished"

View File

@@ -0,0 +1,36 @@
echo Running 4 validator test(s)
echo Running 4 validator test(s) 1> validator-tests.log
echo Running test #1 1>> validator-tests.log
echo Validator comment: 1>> validator-tests.log
files\val.exe < files\tests\validator-tests\01 2>> validator-tests.log
if errorlevel 1 (
echo Validator returned non-zero exit code for a valid test 1>> validator-tests.log
echo Validator returned non-zero exit code for a valid test. See validator-tests.log for validator comment
pause 0
)
echo Running test #2 1>> validator-tests.log
echo Validator comment: 1>> validator-tests.log
files\val.exe < files\tests\validator-tests\02 2>> validator-tests.log
if not errorlevel 1 (
echo Validator returned zero exit code for a invalid test 1>> validator-tests.log
echo Validator returned zero exit code for a invalid test. See validator-tests.log for validator comment
pause 0
)
echo Running test #3 1>> validator-tests.log
echo Validator comment: 1>> validator-tests.log
files\val.exe < files\tests\validator-tests\03 2>> validator-tests.log
if not errorlevel 1 (
echo Validator returned zero exit code for a invalid test 1>> validator-tests.log
echo Validator returned zero exit code for a invalid test. See validator-tests.log for validator comment
pause 0
)
echo Running test #4 1>> validator-tests.log
echo Validator comment: 1>> validator-tests.log
files\val.exe < files\tests\validator-tests\04 2>> validator-tests.log
if not errorlevel 1 (
echo Validator returned zero exit code for a invalid test 1>> validator-tests.log
echo Validator returned zero exit code for a invalid test. See validator-tests.log for validator comment
pause 0
)
del /F /Q validator-tests.log
echo Validator test(s) finished

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env bash
echo "Running 4 validator test(s)"
echo "Running 4 validator test(s)" 1> validator-tests.log
echo "Running test #1" 1>> validator-tests.log
echo "Validator comment:" 1>> validator-tests.log
wine files/val.exe < files/tests/validator-tests/01 2>> validator-tests.log
if [ "$?" -ne "0" ]; then
echo "Validator returned non-zero exit code for a valid test" 1>> validator-tests.log
echo "Validator returned non-zero exit code for a valid test. See validator-tests.log for validator comment"
read
fi
echo "Running test #2" 1>> validator-tests.log
echo "Validator comment:" 1>> validator-tests.log
wine files/val.exe < files/tests/validator-tests/02 2>> validator-tests.log
if [ "$?" -eq "0" ]; then
echo "Validator returned zero exit code for a invalid test" 1>> validator-tests.log
echo "Validator returned zero exit code for a invalid test. See validator-tests.log for validator comment"
read
fi
echo "Running test #3" 1>> validator-tests.log
echo "Validator comment:" 1>> validator-tests.log
wine files/val.exe < files/tests/validator-tests/03 2>> validator-tests.log
if [ "$?" -eq "0" ]; then
echo "Validator returned zero exit code for a invalid test" 1>> validator-tests.log
echo "Validator returned zero exit code for a invalid test. See validator-tests.log for validator comment"
read
fi
echo "Running test #4" 1>> validator-tests.log
echo "Validator comment:" 1>> validator-tests.log
wine files/val.exe < files/tests/validator-tests/04 2>> validator-tests.log
if [ "$?" -eq "0" ]; then
echo "Validator returned zero exit code for a invalid test" 1>> validator-tests.log
echo "Validator returned zero exit code for a invalid test. See validator-tests.log for validator comment"
read
fi
rm -f validator-tests.log
echo "Validator test(s) finished"

View File

@@ -0,0 +1,62 @@
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
#define MAX 101000
int n, k;
int a[MAX];
map<int, int> nxt;
map<int, int> prv;
int main() {
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i < n; i++) {
nxt[a[i]] = a[i + 1];
}
for (int i = 2; i <= n; i++) {
prv[a[i]] = a[i - 1];
}
int last = a[n];
for (int i = 1; i <= k; i++) {
int type;
scanf("%d", &type);
if (type == 1) {
int x, y;
scanf("%d %d", &x, &y);
tie(nxt[x], prv[x], nxt[prv[y]], prv[y]) = {y, prv[y], x, x};
} else if (type == 2) {
int x;
scanf("%d", &x);
nxt[last] = x;
prv[x] = last;
last = x;
} else if (type == 3) {
int x;
scanf("%d", &x);
tie(nxt[prv[x]], prv[nxt[x]]) = {nxt[x], prv[x]};
if (last == x) last = prv[x];
nxt[x] = prv[x] = 0;
}
}
vector<int> ans;
int x = last;
while (x != 0) {
ans.push_back(x);
x = prv[x];
}
printf("%d\n", (int)ans.size());
for (int i = (int)ans.size() - 1; i >= 0; i--) {
printf("%d ", ans[i]);
}
printf("\n");
return 0;
}

View File

@@ -0,0 +1,4 @@
File name: nyatl_ok.cpp
Tag: ACCEPTED
Author: Nyatl
Change time: Mon Apr 07 21:16:54 MSK 2025

Binary file not shown.

View File

@@ -0,0 +1,54 @@
#include <bits/stdc++.h>
using namespace std;
void F() {
int n, m;
cin >> n >> m;
list<int> a;
map<int, list<int>::iterator> mp;
for (int i = 0; i < n; i++) {
int b;
cin >> b;
a.push_back(b);
mp[b] = prev(a.end());
}
while (m--) {
int t;
cin >> t;
if (t == 1) {
int x, y;
cin >> x >> y;
a.insert(mp[y], x);
mp[x] = prev(mp[y]);
}
if (t == 2) {
int x;
cin >> x;
a.push_back(x);
mp[x] = prev(a.end());
}
if (t == 3) {
int x;
cin >> x;
a.erase(mp[x]);
}
}
cout << a.size() << '\n';
for (auto i : a)
cout << i << ' ';
cout << '\n';
}
int main() {
#ifdef KRAKOZAYBRA
FILE* stream;
freopen_s(&stream, "input.txt", "r", stdin);
//freopen_s(&stream, "output.txt", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
int _t = 1;
//cin >> _t;
while (_t--)
F();
}

View File

@@ -0,0 +1,4 @@
File name: valavshonok_OK.cpp
Tag: MAIN
Author: valavshonok
Change time: Tue Apr 01 00:12:51 MSK 2025

Binary file not shown.

View File

@@ -0,0 +1,8 @@
7 6
1 2 3 4 5 6 7
1 8 3
2 9
3 3
1 3 9
2 10
3 1

View File

@@ -0,0 +1,2 @@
9
2 8 4 5 6 7 3 9 10

View File

@@ -0,0 +1,13 @@
В первой строке заданы два целых числа $n$ и $m$ $(1 \le n, m \le 10^5)$~--- текущее число студентов в очереди и количество изменений.
В следующей строке задается $n$ целых \textbf{различных} чисел $a_1, a_2, \cdots , a_n$ $(1 \le a_i \le 10^9)$, где $a_i$~--- номер студента, который стоит на $i$-й позиции в очереди.
В следующих $m$ строках идет описание запросов изменения очереди.
В каждой строке в зависимости от типа запроса задается два или три числа. Первое число $t_j$ $(1 \le t_j \le 3)$~--- тип события, которое произошло в $j$-ю минуту.
Если $t_j = \textbf{1}$, то в строке задается еще 2 числа $x$ $(1 \le x_j \le 10^9)$ и $y$ $(1 \le y_j \le 10^9)$~--- номер студента, который пришел, и номер студента, перед которым он встанет в очереди. Гарантируется, что студент с номером $x$ ещё не занял очередь, а студент с номером $y$ уже стоит в ней.
Если $t_j = \textbf{2}$, то в строке задается еще 1 число $x$ $(1 \le x_j \le 10^9)$~--- номер студента, который пришел и встал в конец очереди. Гарантируется, что студент с номером $x$ ещё не занял очередь.
Если $t_j = \textbf{3}$, то в строке задается еще 1 число $x$ $(1 \le x_j \le 10^9)$~--- номер студента, который ушел из очереди. Гарантируется, что студент с номером $x$ стоит в очереди.

View File

@@ -0,0 +1,16 @@
В честь юбилея ректорат ЮФУ решил запустить акцию <<Сто и десять кексов>>. В каждом корпусе университета открылась лавка с кексами, в которой каждый студент может получить бесплатные кексы.
Не прошло и пары минут после открытия, как к лавкам набежали студенты и образовалось много очередей. Но самая большая очередь образовалась в главном корпусе ЮФУ. Изначально в этой очереди стояло $n$ студентов, но потом в течение следующих $m$ минут какие-то студенты приходили и вставали в очередь, а какие-то уходили.
За каждым студентом закреплен номер его зачетной книжки, будем называть это число номером студента. У каждого студента будет уникальный номер, по которому можно однозначно его идентифицировать. Будем считать, что каждую минуту происходило одно из следующих событий:
\begin{enumerate}
\item Студент с номером $x$ пришел и встал перед студентом с номером $y$;
\item Студент с номером $x$ пришел и встал в конец очереди;
\item Студент с номером $x$ ушел из очереди; возможно, он потом вернется.
\end{enumerate}
Аналитикам стало интересно, а какой будет очередь после $m$ минут?
Помогите им и сообщите конечное состояние очереди.

View File

@@ -0,0 +1 @@
Очередь за кексами

View File

@@ -0,0 +1,31 @@
Изначально очередь выглядит следующим образом:
\includegraphics{o1.png}
В первую минуту приходит студент с номером 8 и встает перед студентом с номером 3.
\includegraphics{o2.png}
Потом студент с номером 9 встает в конец очереди.
\includegraphics{o3.png}
Студент с номером 3 уходит из очереди.
\includegraphics{o4.png}
Потом он возвращается и становится перед студентом с номером 9.
\includegraphics{o5.png}
После в конец очереди становится студент с номером 10.
\includegraphics{o6.png}
И студент с номером 1 уходит из очереди.
\includegraphics{o7.png}
После $m$ событий очередь имеет следующий вид:
\includegraphics{o8.png}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,3 @@
В первой строке выведите одно число $|a|$~--- длину очереди после выполнения всех запросов изменения.
В следующей строке выведите $|a|$ чисел $a_1, a_2, \cdots , a_{|a|}$, где $a_i$~--- номер студента, который стоит на $i$-й позиции в очереди.

View File

@@ -0,0 +1,15 @@
Давайте просто промоделируем все действия.
Заведем список элементов, а также сохраним по ключу $x$ указатель на элемент списка. Мы можем это сделать, так как все элементы различны. Например, в С++ можно просто завести коллекцию list<int>, а также map<int, list<int>::iterator> или реализовать свой список.
Теперь мы можем легко обрабатывать все запросы, а в конце просто выведем весь список.
Запрос 1-го типа можно обработать так: просто берем по ключу указатель на нужный элемент и вставляем перед ним другой элемент, останется только по ключу $x$ записать указатель на новый элемент.
Запрос 2-го типа~--- просто добавить в список элемент в конец и сохранить на него указатель.
Запрос 3-го типа~--- удаляем из списка элемент по его указателю.
В конце просто выводим массив.
Итоговая сложность $O(mlog(n))$

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,318 @@
.problem-statement {
margin: 0.5em auto 2em auto;
font-family: verdana,serif;
line-height: 1.5em;
font-size: 14px;
max-width: 1024px;
}
.problem-statement .epigraph {
margin-left: 67%;
width: 33%;
}
.problem-statement .epigraph-text {
}
.problem-statement .epigraph-source {
border-top: 1px solid #888;
text-align: right;
}
.problem-statement .lstlisting {
padding: 0.5em;
background-color: #f2f2f2;
}
.problem-statement .tex-tabular {
margin: 1em 0;
border-collapse: collapse;
border-spacing: 0;
}
.problem-statement .tex-tabular td {
padding: 0.15em 0.7em;
}
.problem-statement .tex-tabular .tex-tabular-border-left {
border-left: 1px solid;
}
.problem-statement .tex-tabular .tex-tabular-border-right {
border-right: 1px solid;
}
.problem-statement .tex-tabular .tex-tabular-border-top {
border-top: 1px solid;
}
.problem-statement .tex-tabular .tex-tabular-border-bottom {
border-bottom: 1px solid;
}
.problem-statement .tex-tabular .tex-tabular-text-align-left {
text-align: left;
}
.problem-statement .tex-tabular .tex-tabular-text-align-center {
text-align: center;
}
.problem-statement .tex-tabular .tex-tabular-text-align-right {
text-align: right;
}
.problem-statement p {
margin: 0 0 1em 0;
}
.problem-statement p a, .problem-statement ul a, .problem-statement ol a, .problem-statement td a {
margin: 0;
}
.problem-statement .header {
margin-bottom: 1em;
text-align: center;
}
.problem-statement .header .title {
font-size: 150%;
margin-bottom: 0.25em;
}
.problem-statement .header .title {
font-size: 150%;
font-family: arial, serif;
}
.problem-statement ul {
list-style: disc outside;
margin: 0 0 1em 0;
}
.problem-statement ol {
list-style: decimal outside;
margin: 0 0 1em 0;
}
.problem-statement li {
line-height: 1.5em;
margin-left: 3em;
}
.problem-statement .property-title {
display: inline;
}
.problem-statement .property-title:after {
content: ": ";
}
.problem-statement .time-limit, .problem-statement .memory-limit, .problem-statement .input-file, .problem-statement .output-file {
margin: 0 auto;
}
.problem-statement .legend {
margin-bottom: 1em;
}
.problem-statement .tutorial {
margin-bottom: 1em;
}
.problem-statement .section-title {
font-family: arial, serif;
font-size: 115%;
font-weight: bold;
}
.problem-statement .input-specification,
.problem-statement .output-specification,
.problem-statement .sample-tests,
.problem-statement .author,
.problem-statement .resource,
.problem-statement .date {
/*margin-bottom: 1em;*/
}
.problem-statement .output-specification {
margin-bottom: 1em;
}
.problem-statement .sample-tests .sample-test {
}
.problem-statement .sample-tests .input, .problem-statement .sample-tests .output {
border: 1px solid #888;
}
.problem-statement .sample-tests .output {
margin-bottom: 1em;
position: relative;
top: -1px;
}
.problem-statement .sample-tests pre {
line-height: 1.25em;
padding: 0.25em;
margin: 0;
background-color: #efefef;
}
.problem-statement .sample-tests .title {
font-family: arial, serif;
padding: 0.25em;
border-bottom: 1px solid #888;
text-transform: lowercase;
font-weight: bold;
}
.problem-statement .tex-formula {
vertical-align: middle;
margin: 0;
border:medium none;
position: relative;
bottom: 2px;
}
.problem-statement .tex-span {
font-size: 125%;
font-family: times new roman, serif;
white-space: nowrap;
}
.problem-statement .tex-font-size-tiny {
font-size: 70%;
}
.problem-statement .tex-font-size-script {
font-size: 75%;
}
.problem-statement .tex-font-size-footnotes {
font-size: 85%;
}
.problem-statement .tex-font-size-small {
font-size: 85%;
}
.problem-statement .tex-font-size-normal {
font-size: 100%;
}
.problem-statement .tex-font-size-large-1 {
font-size: 115%;
}
.problem-statement .tex-font-size-large-2 {
font-size: 130%;
}
.problem-statement .tex-font-size-large-3 {
font-size: 145%;
}
.problem-statement .tex-font-size-huge-1 {
font-size: 175%;
}
.problem-statement .tex-font-size-huge-2 {
font-size: 200%;
}
.problem-statement .tex-font-style-rm {
}
.problem-statement .tex-font-style-striked {
text-decoration: line-through;
}
.problem-statement .tex-font-style-underline {
text-decoration: underline;
}
.problem-statement .tex-font-style-sf {
font-family: arial, serif;
}
.problem-statement .tex-font-style-tt {
font-size: 110%;
font-family: courier new, serif;
}
.problem-statement .tex-font-style-md {
}
.problem-statement .tex-font-style-bf {
font-weight: bold;
}
.problem-statement .tex-font-style-up {
}
.problem-statement .tex-font-style-it {
font-style: italic;
}
.problem-statement .tex-font-style-sl {
font-style: italic;
}
.problem-statement .tex-font-style-sc {
text-transform: uppercase;
}
.problem-statement .tex-graphics {
max-width: 95%;
display: block;
}
.problem-statement .tex-tabular .tex-graphics {
max-width: 100%;
}
.problem-statement .input-output-copier {
font-size: 0.75rem;
float: right;
color: #888;
padding: 3px;
cursor: pointer;
border: 1px solid rgb(185, 185, 185);
line-height: 0.8rem;
text-transform: none;
}
.problem-statement .input-output-copier:hover {
background-color: #def;
}
.problem-statement .test-example-line-even {
background-color: #E0E0E0;
}
.statement-footnote {
font-size: 85%;
position: relative;
}
.statement-footnote::before {
content: "";
position: absolute;
top: -2px;
width: 25%;
border-top: 1px solid #888;
}
.statement-footnote p {
margin-bottom: 0.5em;
}
.statement-footnote p:last-child {
margin-bottom: 1em;
}
.problem-statement .header .input-standard,
.problem-statement .header .output-standard {
display: none;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
<HTML><HEAD><META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META content="no-cache" http-equiv="pragma">
<META content="-1" http-equiv="expires">
<META content="text/html;charset=UTF-8" http-equiv="content-type">
<LINK href="problem-statement.css" rel="stylesheet" type="text/css">
<TITLE>Очередь за кексами</TITLE>
<SCRIPT type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$$$','$$$']], displayMath: [['$$$$$$','$$$$$$']]}
});
</SCRIPT>
<SCRIPT async="" src="https://polygon.codeforces.com/lib/MathJax/MathJax.js?config=TeX-MML-AM_CHTML" type="text/javascript">
</SCRIPT>
</HEAD><BODY>
<DIV class="problem-statement"><DIV class="header"><DIV class="title">Очередь за кексами</DIV></DIV><DIV class="tutorial"><P>Давайте просто промоделируем все действия.</P><P>Заведем список элементов, а также сохраним по ключу $$$x$$$ указатель на элемент списка. Мы можем это сделать, так как все элементы различны. Например, в С++ можно просто завести коллекцию list&lt;int&gt;, а также map&lt;int, list&lt;int&gt;::iterator&gt; или реализовать свой список.</P><P>Теперь мы можем легко обрабатывать все запросы, а в конце просто выведем весь список.</P><P>Запрос 1-го типа можно обработать так: просто берем по ключу указатель на нужный элемент и вставляем перед ним другой элемент, останется только по ключу $$$x$$$ записать указатель на новый элемент.</P><P>Запрос 2-го типа&nbsp;&mdash; просто добавить в список элемент в конец и сохранить на него указатель.</P><P>Запрос 3-го типа&nbsp;&mdash; удаляем из списка элемент по его указателю.</P><P>В конце просто выводим массив.</P><P>Итоговая сложность $$$O(mlog(n))$$$</P></DIV></DIV>
</BODY></HTML>

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,8 @@
7 6
1 2 3 4 5 6 7
1 8 3
2 9
3 3
1 3 9
2 10
3 1

View File

@@ -0,0 +1,2 @@
9
2 8 4 5 6 7 3 9 10

View File

@@ -0,0 +1,8 @@
MU<EFBFBD>7 6
1 2 3 4 5 6 7
1 8 3
2 9
3 3
1 3 9
2 10
3 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,81 @@
\begin{problem}{Очередь за кексами}{стандартный ввод}{стандартный вывод}{1 секунда}{256 мегабайт}
В честь юбилея ректорат ЮФУ решил запустить акцию <<Сто и десять кексов>>. В каждом корпусе университета открылась лавка с кексами, в которой каждый студент может получить бесплатные кексы.
Не прошло и пары минут после открытия, как к лавкам набежали студенты и образовалось много очередей. Но самая большая очередь образовалась в главном корпусе ЮФУ. Изначально в этой очереди стояло $n$ студентов, но потом в течение следующих $m$ минут какие-то студенты приходили и вставали в очередь, а какие-то уходили.
За каждым студентом закреплен номер его зачетной книжки, будем называть это число номером студента. У каждого студента будет уникальный номер, по которому можно однозначно его идентифицировать. Будем считать, что каждую минуту происходило одно из следующих событий:
\begin{enumerate}
\item Студент с номером $x$ пришел и встал перед студентом с номером $y$;
\item Студент с номером $x$ пришел и встал в конец очереди;
\item Студент с номером $x$ ушел из очереди; возможно, он потом вернется.
\end{enumerate}
Аналитикам стало интересно, а какой будет очередь после $m$ минут?
Помогите им и сообщите конечное состояние очереди.
\InputFile
В первой строке заданы два целых числа $n$ и $m$ $(1 \le n, m \le 10^5)$~--- текущее число студентов в очереди и количество изменений.
В следующей строке задается $n$ целых \textbf{различных} чисел $a_1, a_2, \cdots , a_n$ $(1 \le a_i \le 10^9)$, где $a_i$~--- номер студента, который стоит на $i$-й позиции в очереди.
В следующих $m$ строках идет описание запросов изменения очереди.
В каждой строке в зависимости от типа запроса задается два или три числа. Первое число $t_j$ $(1 \le t_j \le 3)$~--- тип события, которое произошло в $j$-ю минуту.
Если $t_j = \textbf{1}$, то в строке задается еще 2 числа $x$ $(1 \le x_j \le 10^9)$ и $y$ $(1 \le y_j \le 10^9)$~--- номер студента, который пришел, и номер студента, перед которым он встанет в очереди. Гарантируется, что студент с номером $x$ ещё не занял очередь, а студент с номером $y$ уже стоит в ней.
Если $t_j = \textbf{2}$, то в строке задается еще 1 число $x$ $(1 \le x_j \le 10^9)$~--- номер студента, который пришел и встал в конец очереди. Гарантируется, что студент с номером $x$ ещё не занял очередь.
Если $t_j = \textbf{3}$, то в строке задается еще 1 число $x$ $(1 \le x_j \le 10^9)$~--- номер студента, который ушел из очереди. Гарантируется, что студент с номером $x$ стоит в очереди.
\OutputFile
В первой строке выведите одно число $|a|$~--- длину очереди после выполнения всех запросов изменения.
В следующей строке выведите $|a|$ чисел $a_1, a_2, \cdots , a_{|a|}$, где $a_i$~--- номер студента, который стоит на $i$-й позиции в очереди.
\Example
\begin{example}
\exmpfile{example.01}{example.01.a}%
\end{example}
\Note
Изначально очередь выглядит следующим образом:
\includegraphics{o1.png}
В первую минуту приходит студент с номером 8 и встает перед студентом с номером 3.
\includegraphics{o2.png}
Потом студент с номером 9 встает в конец очереди.
\includegraphics{o3.png}
Студент с номером 3 уходит из очереди.
\includegraphics{o4.png}
Потом он возвращается и становится перед студентом с номером 9.
\includegraphics{o5.png}
После в конец очереди становится студент с номером 10.
\includegraphics{o6.png}
И студент с номером 1 уходит из очереди.
\includegraphics{o7.png}
После $m$ событий очередь имеет следующий вид:
\includegraphics{o8.png}
\end{problem}

View File

@@ -0,0 +1,19 @@
\begin{tutorial}{Очередь за кексами}
Давайте просто промоделируем все действия.
Заведем список элементов, а также сохраним по ключу $x$ указатель на элемент списка. Мы можем это сделать, так как все элементы различны. Например, в С++ можно просто завести коллекцию list<int>, а также map<int, list<int>::iterator> или реализовать свой список.
Теперь мы можем легко обрабатывать все запросы, а в конце просто выведем весь список.
Запрос 1-го типа можно обработать так: просто берем по ключу указатель на нужный элемент и вставляем перед ним другой элемент, останется только по ключу $x$ записать указатель на новый элемент.
Запрос 2-го типа~--- просто добавить в список элемент в конец и сохранить на него указатель.
Запрос 3-го типа~--- удаляем из списка элемент по его указателю.
В конце просто выводим массив.
Итоговая сложность $O(mlog(n))$
\end{tutorial}

1
exam-queue-17/tags Normal file
View File

@@ -0,0 +1 @@
realization

8
exam-queue-17/tests/01 Normal file
View File

@@ -0,0 +1,8 @@
7 6
1 2 3 4 5 6 7
1 8 3
2 9
3 3
1 3 9
2 10
3 1

103
exam-queue-17/wipe.bat Normal file
View File

@@ -0,0 +1,103 @@
rem *** tests ***
del tests\01.a
del tests\02
del tests\02.a
del tests\03
del tests\03.a
del tests\04
del tests\04.a
del tests\05
del tests\05.a
del tests\06
del tests\06.a
del tests\07
del tests\07.a
del tests\08
del tests\08.a
del tests\09
del tests\09.a
del tests\10
del tests\10.a
del tests\11
del tests\11.a
del tests\12
del tests\12.a
del tests\13
del tests\13.a
del tests\14
del tests\14.a
del tests\15
del tests\15.a
del tests\16
del tests\16.a
del tests\17
del tests\17.a
del tests\18
del tests\18.a
del tests\19
del tests\19.a
del tests\20
del tests\20.a
del tests\21
del tests\21.a
del tests\22
del tests\22.a
del tests\23
del tests\23.a
del tests\24
del tests\24.a
del tests\25
del tests\25.a
del tests\26
del tests\26.a
del tests\27
del tests\27.a
del tests\28
del tests\28.a
del tests\29
del tests\29.a
del tests\30
del tests\30.a
del tests\31
del tests\31.a
del tests\32
del tests\32.a
del tests\33
del tests\33.a
del tests\34
del tests\34.a
del tests\35
del tests\35.a
del tests\36
del tests\36.a
del tests\37
del tests\37.a
del tests\38
del tests\38.a
del tests\39
del tests\39.a
del tests\40
del tests\40.a
del tests\41
del tests\41.a
del tests\42
del tests\42.a
del tests\43
del tests\43.a
del tests\44
del tests\44.a
del tests\45
del tests\45.a
del tests\46
del tests\46.a
del tests\47
del tests\47.a
del tests\48
del tests\48.a
del tests\49
del tests\49.a
del tests\50
del tests\50.a
del tests\51
del tests\51.a

104
exam-queue-17/wipe.sh Normal file
View File

@@ -0,0 +1,104 @@
#!/usr/bin/env bash
# *** tests ***
rm -f tests/01.a
rm -f tests/02
rm -f tests/02.a
rm -f tests/03
rm -f tests/03.a
rm -f tests/04
rm -f tests/04.a
rm -f tests/05
rm -f tests/05.a
rm -f tests/06
rm -f tests/06.a
rm -f tests/07
rm -f tests/07.a
rm -f tests/08
rm -f tests/08.a
rm -f tests/09
rm -f tests/09.a
rm -f tests/10
rm -f tests/10.a
rm -f tests/11
rm -f tests/11.a
rm -f tests/12
rm -f tests/12.a
rm -f tests/13
rm -f tests/13.a
rm -f tests/14
rm -f tests/14.a
rm -f tests/15
rm -f tests/15.a
rm -f tests/16
rm -f tests/16.a
rm -f tests/17
rm -f tests/17.a
rm -f tests/18
rm -f tests/18.a
rm -f tests/19
rm -f tests/19.a
rm -f tests/20
rm -f tests/20.a
rm -f tests/21
rm -f tests/21.a
rm -f tests/22
rm -f tests/22.a
rm -f tests/23
rm -f tests/23.a
rm -f tests/24
rm -f tests/24.a
rm -f tests/25
rm -f tests/25.a
rm -f tests/26
rm -f tests/26.a
rm -f tests/27
rm -f tests/27.a
rm -f tests/28
rm -f tests/28.a
rm -f tests/29
rm -f tests/29.a
rm -f tests/30
rm -f tests/30.a
rm -f tests/31
rm -f tests/31.a
rm -f tests/32
rm -f tests/32.a
rm -f tests/33
rm -f tests/33.a
rm -f tests/34
rm -f tests/34.a
rm -f tests/35
rm -f tests/35.a
rm -f tests/36
rm -f tests/36.a
rm -f tests/37
rm -f tests/37.a
rm -f tests/38
rm -f tests/38.a
rm -f tests/39
rm -f tests/39.a
rm -f tests/40
rm -f tests/40.a
rm -f tests/41
rm -f tests/41.a
rm -f tests/42
rm -f tests/42.a
rm -f tests/43
rm -f tests/43.a
rm -f tests/44
rm -f tests/44.a
rm -f tests/45
rm -f tests/45.a
rm -f tests/46
rm -f tests/46.a
rm -f tests/47
rm -f tests/47.a
rm -f tests/48
rm -f tests/48.a
rm -f tests/49
rm -f tests/49.a
rm -f tests/50
rm -f tests/50.a
rm -f tests/51
rm -f tests/51.a

View File

@@ -3,6 +3,7 @@ namespace LiquidCode.Tester.Common.Models;
public class ProblemPackage public class ProblemPackage
{ {
public string WorkingDirectory { get; set; } = string.Empty; public string WorkingDirectory { get; set; } = string.Empty;
public string? ExtractionRoot { get; set; }
public List<TestCase> TestCases { get; set; } = new(); public List<TestCase> TestCases { get; set; } = new();
public string? CheckerPath { get; set; } public string? CheckerPath { get; set; }
public int DefaultTimeLimit { get; set; } = 2000; // milliseconds public int DefaultTimeLimit { get; set; } = 2000; // milliseconds

View File

@@ -136,23 +136,37 @@ public class AnswerGenerationService
return (null, ""); return (null, "");
} }
if (solutionType.StartsWith("python.")) if (solutionType.StartsWith("python"))
{ {
var parts = solutionType.Split('.'); var versionPart = solutionType.Replace("python", string.Empty, StringComparison.OrdinalIgnoreCase)
var version = parts.Length > 1 ? parts[1] : "3"; .Trim('.', ' ');
return ("python", $"3.{version}"); // Map python.3 -> 3.3, python.2 -> 3.2 (approx)
if (string.IsNullOrWhiteSpace(versionPart))
{
return ("python", "3");
}
// Normalize python version; Polygon often uses python.3 or python3.10
versionPart = versionPart.TrimStart('.');
if (!versionPart.Contains('.'))
{
// Assume major version provided, default to CPython minor 10
versionPart = versionPart switch
{
"2" => "2.7",
"3" => "3.10",
_ => $"3.{versionPart}"
};
}
return ("python", versionPart);
} }
if (solutionType.StartsWith("cpp.")) if (solutionType.StartsWith("cpp."))
{ {
// cpp.g++17, cpp.g++20, cpp.g++14 var standard = ExtractCppStandard(solutionType);
if (solutionType.Contains("++20")) return ("cpp", standard);
return ("cpp", "20");
if (solutionType.Contains("++17"))
return ("cpp", "17");
if (solutionType.Contains("++14"))
return ("cpp", "14");
return ("cpp", "17"); // Default to C++17
} }
if (solutionType.StartsWith("java")) if (solutionType.StartsWith("java"))
@@ -178,4 +192,22 @@ public class AnswerGenerationService
_logger.LogWarning("Unknown solution type: {Type}", solutionType); _logger.LogWarning("Unknown solution type: {Type}", solutionType);
return (null, ""); return (null, "");
} }
private static string ExtractCppStandard(string solutionType)
{
var knownStandards = new[] { "26", "23", "20", "17", "14", "11", "03", "98" };
foreach (var standard in knownStandards)
{
if (solutionType.Contains($"++{standard}", StringComparison.OrdinalIgnoreCase) ||
solutionType.Contains($"c++{standard}", StringComparison.OrdinalIgnoreCase))
{
// Normalize 03 to 03, 98 stays 98
return standard.TrimStart('0');
}
}
// Default to modern standard if not specified
return "17";
}
} }

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using LiquidCode.Tester.Worker.Models; using LiquidCode.Tester.Worker.Models;
namespace LiquidCode.Tester.Worker.Services; namespace LiquidCode.Tester.Worker.Services;
@@ -23,57 +25,8 @@ public class CppCompilationService : ICompilationService
try try
{ {
// Write source code to file
await File.WriteAllTextAsync(sourceFilePath, sourceCode); await File.WriteAllTextAsync(sourceFilePath, sourceCode);
return await CompileFileAsync(sourceFilePath, executablePath, version);
// Resolve version-specific configuration
var (compiler, compilerFlags) = ResolveVersion(version);
_logger.LogDebug("Using compiler: {Compiler} with flags: {Flags}", compiler, compilerFlags);
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = compiler,
Arguments = $"{compilerFlags} {sourceFilePath} -o {executablePath}",
WorkingDirectory = workingDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
var output = await process.StandardOutput.ReadToEndAsync();
var error = await process.StandardError.ReadToEndAsync();
await process.WaitForExitAsync();
var compilerOutput = $"{output}\n{error}".Trim();
if (process.ExitCode == 0 && File.Exists(executablePath))
{
_logger.LogInformation("Compilation successful");
return new CompilationResult
{
Success = true,
ExecutablePath = executablePath,
CompilerOutput = compilerOutput
};
}
else
{
_logger.LogWarning("Compilation failed with exit code {ExitCode}", process.ExitCode);
return new CompilationResult
{
Success = false,
ErrorMessage = "Compilation failed",
CompilerOutput = compilerOutput
};
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -86,31 +39,168 @@ public class CppCompilationService : ICompilationService
} }
} }
private (string compiler, string compilerFlags) ResolveVersion(string? version) public async Task<CompilationResult> CompileFileAsync(
string sourceFilePath,
string outputExecutablePath,
string? version = null,
IEnumerable<string>? includeDirectories = null,
IEnumerable<string>? additionalFlags = null)
{ {
// If version is null or "latest", use default configuration _logger.LogInformation("Compiling C++ source {Source} -> {Output} with version {Version}", sourceFilePath, outputExecutablePath, version ?? "latest");
try
{
Directory.CreateDirectory(Path.GetDirectoryName(outputExecutablePath)!);
var (compiler, compilerFlags) = ResolveVersion(version);
_logger.LogDebug("Using compiler: {Compiler} with flags: {Flags}", compiler, string.Join(' ', compilerFlags));
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = compiler,
WorkingDirectory = Path.GetDirectoryName(sourceFilePath) ?? Directory.GetCurrentDirectory(),
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
foreach (var flag in compilerFlags)
{
process.StartInfo.ArgumentList.Add(flag);
}
if (includeDirectories != null)
{
foreach (var includeDir in includeDirectories.Where(d => !string.IsNullOrWhiteSpace(d)))
{
process.StartInfo.ArgumentList.Add($"-I{includeDir}");
}
}
if (additionalFlags != null)
{
foreach (var flag in additionalFlags.Where(f => !string.IsNullOrWhiteSpace(f)))
{
process.StartInfo.ArgumentList.Add(flag);
}
}
process.StartInfo.ArgumentList.Add(sourceFilePath);
process.StartInfo.ArgumentList.Add("-o");
process.StartInfo.ArgumentList.Add(outputExecutablePath);
process.Start();
var stdOutTask = process.StandardOutput.ReadToEndAsync();
var stdErrTask = process.StandardError.ReadToEndAsync();
await process.WaitForExitAsync();
var compilerOutput = $"{await stdOutTask}\n{await stdErrTask}".Trim();
if (process.ExitCode == 0 && File.Exists(outputExecutablePath))
{
_logger.LogInformation("Compilation successful");
return new CompilationResult
{
Success = true,
ExecutablePath = outputExecutablePath,
CompilerOutput = compilerOutput
};
}
_logger.LogWarning("Compilation failed with exit code {ExitCode}", process.ExitCode);
return new CompilationResult
{
Success = false,
ErrorMessage = "Compilation failed",
CompilerOutput = compilerOutput
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during compilation");
return new CompilationResult
{
Success = false,
ErrorMessage = $"Compilation error: {ex.Message}"
};
}
}
private (string compiler, List<string> compilerFlags) ResolveVersion(string? version)
{
var defaultCompiler = _configuration["Cpp:Compiler"] ?? "g++";
var defaultFlags = SplitFlags(_configuration["Cpp:CompilerFlags"] ?? "-O2 -std=c++17 -Wall");
if (string.IsNullOrEmpty(version) || version.Equals("latest", StringComparison.OrdinalIgnoreCase)) if (string.IsNullOrEmpty(version) || version.Equals("latest", StringComparison.OrdinalIgnoreCase))
{ {
var compiler = _configuration["Cpp:Compiler"] ?? "g++"; return (defaultCompiler, defaultFlags);
var compilerFlags = _configuration["Cpp:CompilerFlags"] ?? "-O2 -std=c++17 -Wall";
return (compiler, compilerFlags);
} }
// Try to find version-specific configuration
var versionKey = $"Cpp:Versions:{version}"; var versionKey = $"Cpp:Versions:{version}";
var versionCompiler = _configuration[$"{versionKey}:Compiler"]; var versionCompiler = _configuration[$"{versionKey}:Compiler"];
var versionFlags = _configuration[$"{versionKey}:CompilerFlags"]; var versionFlagsValue = _configuration[$"{versionKey}:CompilerFlags"];
if (!string.IsNullOrEmpty(versionCompiler)) if (!string.IsNullOrEmpty(versionCompiler) || !string.IsNullOrEmpty(versionFlagsValue))
{ {
var resolvedFlags = !string.IsNullOrEmpty(versionFlagsValue)
? SplitFlags(versionFlagsValue)
: defaultFlags;
_logger.LogInformation("Using C++ version {Version} configuration", version); _logger.LogInformation("Using C++ version {Version} configuration", version);
return (versionCompiler, versionFlags ?? "-O2 -Wall"); return (versionCompiler ?? defaultCompiler, resolvedFlags);
}
var normalized = NormalizeCppVersion(version);
if (normalized != null)
{
var flagsWithoutStd = defaultFlags
.Where(flag => !flag.StartsWith("-std=", StringComparison.OrdinalIgnoreCase))
.ToList();
flagsWithoutStd.Add($"-std=c++{normalized}");
_logger.LogInformation("Using inferred C++ standard c++{Standard}", normalized);
return (defaultCompiler, flagsWithoutStd);
} }
// Version not found, use default and log warning
_logger.LogWarning("C++ version {Version} not found in configuration, using default", version); _logger.LogWarning("C++ version {Version} not found in configuration, using default", version);
var defaultCompiler = _configuration["Cpp:Compiler"] ?? "g++";
var defaultFlags = _configuration["Cpp:CompilerFlags"] ?? "-O2 -std=c++17 -Wall";
return (defaultCompiler, defaultFlags); return (defaultCompiler, defaultFlags);
} }
private static List<string> SplitFlags(string flags) =>
flags.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.ToList();
private static string? NormalizeCppVersion(string version)
{
var cleaned = version.Trim().ToLowerInvariant();
cleaned = cleaned.Replace("c++", string.Empty, StringComparison.OrdinalIgnoreCase)
.Replace("gnu++", string.Empty, StringComparison.OrdinalIgnoreCase)
.Trim('+', ' ');
cleaned = cleaned switch
{
"2b" => "23",
"2a" => "20",
"1z" => "17",
"0x" => "11",
_ => cleaned
};
return cleaned switch
{
"26" => "26",
"23" => "23",
"20" => "20",
"17" => "17",
"14" => "14",
"11" => "11",
_ => null
};
}
} }

View File

@@ -51,6 +51,12 @@ public class OutputCheckerService : IOutputCheckerService
lines.RemoveAt(lines.Count - 1); lines.RemoveAt(lines.Count - 1);
} }
// Remove leading empty lines
while (lines.Count > 0 && string.IsNullOrWhiteSpace(lines[0]))
{
lines.RemoveAt(0);
}
return string.Join("\n", lines); return string.Join("\n", lines);
} }

View File

@@ -1,4 +1,10 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO.Compression; using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using LiquidCode.Tester.Common.Models; using LiquidCode.Tester.Common.Models;
namespace LiquidCode.Tester.Worker.Services; namespace LiquidCode.Tester.Worker.Services;
@@ -35,12 +41,15 @@ public class PackageParserService : IPackageParserService
using var archive = new ZipArchive(packageStream, ZipArchiveMode.Read); using var archive = new ZipArchive(packageStream, ZipArchiveMode.Read);
archive.ExtractToDirectory(workingDirectory); archive.ExtractToDirectory(workingDirectory);
// Check if this is a Polygon package (has problem.xml) // Check if this is a Polygon package (search for problem.xml)
var problemXmlPath = Path.Combine(workingDirectory, "problem.xml"); var problemXmlPath = Directory.EnumerateFiles(workingDirectory, "problem.xml", SearchOption.AllDirectories)
if (File.Exists(problemXmlPath)) .FirstOrDefault();
if (!string.IsNullOrEmpty(problemXmlPath))
{ {
_logger.LogInformation("Detected Polygon package format (problem.xml found)"); var packageRoot = Path.GetDirectoryName(problemXmlPath)!;
return await ParsePolygonPackageAsync(workingDirectory, problemXmlPath); _logger.LogInformation("Detected Polygon package format (problem.xml found at {ProblemXml})", problemXmlPath);
return await ParsePolygonPackageAsync(packageRoot, problemXmlPath, workingDirectory);
} }
// Fall back to legacy format (.in/.out files) // Fall back to legacy format (.in/.out files)
@@ -54,89 +63,120 @@ public class PackageParserService : IPackageParserService
} }
} }
private async Task<ProblemPackage> ParsePolygonPackageAsync(string workingDirectory, string problemXmlPath) private async Task<ProblemPackage> ParsePolygonPackageAsync(string packageRoot, string problemXmlPath, string extractionRoot)
{ {
var descriptor = _polygonParser.ParseProblemXml(problemXmlPath); var descriptor = _polygonParser.ParseProblemXml(problemXmlPath);
if (descriptor == null) if (descriptor == null)
{ {
_logger.LogWarning("Failed to parse problem.xml, falling back to legacy format"); _logger.LogWarning("Failed to parse problem.xml, falling back to legacy format");
return await ParseLegacyPackage(workingDirectory); return await ParseLegacyPackage(packageRoot, extractionRoot);
} }
var package = new ProblemPackage var package = new ProblemPackage
{ {
WorkingDirectory = workingDirectory, WorkingDirectory = packageRoot,
ExtractionRoot = extractionRoot,
DefaultTimeLimit = descriptor.TimeLimitMs, DefaultTimeLimit = descriptor.TimeLimitMs,
DefaultMemoryLimit = descriptor.MemoryLimitMb DefaultMemoryLimit = descriptor.MemoryLimitMb
}; };
// Collect test file paths and check which answers are missing var buildDirectory = Path.Combine(packageRoot, ".lc-build");
var inputPaths = new List<string>(); Directory.CreateDirectory(buildDirectory);
var answerPaths = new List<string>();
var missingAnswerPaths = new List<string>();
var missingAnswerInputs = new List<string>();
for (int i = 1; i <= descriptor.TestCount; i++) var compiledExecutables = await CompilePolygonExecutablesAsync(descriptor, packageRoot, buildDirectory);
package.CheckerPath = await CompileCheckerForPackageAsync(descriptor, packageRoot, buildDirectory)
?? await FindAndCompileCheckerAsync(packageRoot);
var validatorPath = await CompileValidatorAsync(descriptor, packageRoot, buildDirectory, compiledExecutables);
await GenerateAndValidateTestsAsync(descriptor, packageRoot, compiledExecutables, validatorPath);
var testIndices = descriptor.Tests.Count > 0
? descriptor.Tests.Select(t => t.Index).Distinct().OrderBy(i => i).ToList()
: Enumerable.Range(1, descriptor.TestCount > 0 ? descriptor.TestCount : 0).ToList();
if (testIndices.Count == 0)
{ {
var inputPath = Path.Combine(workingDirectory, _logger.LogWarning("No test definitions discovered in problem.xml; falling back to filesystem scan");
string.Format(descriptor.InputPathPattern.Replace("%02d", "{0:D2}"), i)); return await ParseLegacyPackage(packageRoot, extractionRoot);
var answerPath = Path.Combine(workingDirectory, }
string.Format(descriptor.AnswerPathPattern.Replace("%02d", "{0:D2}"), i));
if (!File.Exists(inputPath)) var inputs = new List<(int index, string inputPath)>();
var answers = new Dictionary<int, string>();
foreach (var testIndex in testIndices)
{
var inputRelative = FormatPolygonPattern(descriptor.InputPathPattern, testIndex);
var inputFullPath = Path.Combine(packageRoot, NormalizeRelativePath(inputRelative));
if (!File.Exists(inputFullPath))
{ {
_logger.LogWarning("Input file not found: {InputPath}", inputPath); _logger.LogWarning("Input file not found for test {Index}: {RelativePath}", testIndex, inputRelative);
continue; continue;
} }
inputPaths.Add(inputPath); var answerRelative = FormatPolygonPattern(descriptor.AnswerPathPattern, testIndex);
answerPaths.Add(answerPath); var answerFullPath = Path.Combine(packageRoot, NormalizeRelativePath(answerRelative));
inputs.Add((testIndex, inputFullPath));
answers[testIndex] = answerFullPath;
}
var missingAnswerInputs = new List<string>();
var missingAnswerPaths = new List<string>();
foreach (var (index, inputPath) in inputs)
{
if (!answers.TryGetValue(index, out var answerPath))
{
continue;
}
if (!File.Exists(answerPath)) if (!File.Exists(answerPath))
{ {
missingAnswerPaths.Add(answerPath);
missingAnswerInputs.Add(inputPath); missingAnswerInputs.Add(inputPath);
missingAnswerPaths.Add(answerPath);
} }
} }
// Generate missing answer files if we have a main solution
if (missingAnswerPaths.Count > 0) if (missingAnswerPaths.Count > 0)
{ {
_logger.LogInformation("Found {Count} tests without answer files, attempting to generate them", _logger.LogInformation("Found {Count} tests without answers, attempting to generate them", missingAnswerPaths.Count);
missingAnswerPaths.Count);
var generated = await _answerGenerator.GenerateAnswersAsync( var generated = await _answerGenerator.GenerateAnswersAsync(
descriptor, descriptor,
workingDirectory, packageRoot,
missingAnswerInputs, missingAnswerInputs,
missingAnswerPaths); missingAnswerPaths);
if (generated) if (!generated)
{ {
_logger.LogInformation("Successfully generated answer files"); _logger.LogWarning("Failed to generate answer files, affected tests will be skipped");
} }
else else
{ {
_logger.LogWarning("Failed to generate answer files, tests without answers will be skipped"); _logger.LogInformation("Answer files generated successfully");
} }
} }
// Now create test cases for all tests that have answer files foreach (var (index, inputPath) in inputs.OrderBy(item => item.index))
for (int i = 0; i < inputPaths.Count; i++)
{ {
var inputPath = inputPaths[i]; if (!answers.TryGetValue(index, out var answerPath))
var answerPath = answerPaths[i]; {
continue;
}
if (!File.Exists(answerPath)) if (!File.Exists(answerPath))
{ {
_logger.LogWarning("Answer file not found: {AnswerPath} (skipping test)", answerPath); _logger.LogWarning("Answer file not found for test {Index}: {AnswerPath}", index, answerPath);
continue; continue;
} }
package.TestCases.Add(new TestCase package.TestCases.Add(new TestCase
{ {
Number = i + 1, Number = index,
InputFilePath = inputPath, InputFilePath = inputPath,
OutputFilePath = answerPath, OutputFilePath = answerPath,
TimeLimit = descriptor.TimeLimitMs, TimeLimit = descriptor.TimeLimitMs,
@@ -144,26 +184,23 @@ public class PackageParserService : IPackageParserService
}); });
} }
// Look for and compile checker
package.CheckerPath = await FindAndCompileCheckerAsync(workingDirectory);
if (package.TestCases.Count == 0) if (package.TestCases.Count == 0)
{ {
_logger.LogWarning("No test cases with answer files found! Expected format: {InputPattern} -> {AnswerPattern}", _logger.LogWarning("No test cases with answer files found for Polygon package");
descriptor.InputPathPattern, descriptor.AnswerPathPattern);
} }
_logger.LogInformation("Parsed Polygon package with {TestCount} tests (out of {TotalTests} in problem.xml)", _logger.LogInformation("Parsed Polygon package with {TestCount} tests (declared {TotalTests})",
package.TestCases.Count, descriptor.TestCount); package.TestCases.Count, descriptor.TestCount);
return package; return package;
} }
private async Task<ProblemPackage> ParseLegacyPackage(string workingDirectory) private async Task<ProblemPackage> ParseLegacyPackage(string workingDirectory, string? extractionRoot = null)
{ {
var package = new ProblemPackage var package = new ProblemPackage
{ {
WorkingDirectory = workingDirectory WorkingDirectory = workingDirectory,
ExtractionRoot = extractionRoot ?? workingDirectory
}; };
// Find tests directory // Find tests directory
@@ -193,7 +230,7 @@ public class PackageParserService : IPackageParserService
package.TestCases.Add(new TestCase package.TestCases.Add(new TestCase
{ {
Number = i + 1, Number = package.TestCases.Count + 1,
InputFilePath = inputFile, InputFilePath = inputFile,
OutputFilePath = outputFile, OutputFilePath = outputFile,
TimeLimit = package.DefaultTimeLimit, TimeLimit = package.DefaultTimeLimit,
@@ -213,6 +250,447 @@ public class PackageParserService : IPackageParserService
return package; return package;
} }
private async Task<Dictionary<string, string>> CompilePolygonExecutablesAsync(
PolygonProblemDescriptor descriptor,
string packageRoot,
string buildDirectory)
{
var compiled = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var executable in descriptor.Executables)
{
if (string.IsNullOrWhiteSpace(executable.SourcePath))
{
continue;
}
var alias = !string.IsNullOrWhiteSpace(executable.Name)
? executable.Name
: Path.GetFileNameWithoutExtension(executable.SourcePath);
if (string.IsNullOrWhiteSpace(alias))
{
continue;
}
var sourceFullPath = Path.Combine(packageRoot, NormalizeRelativePath(executable.SourcePath));
if (!File.Exists(sourceFullPath))
{
_logger.LogWarning("Executable source not found: {Path}", executable.SourcePath);
continue;
}
if (IsCppAsset(executable.Type, sourceFullPath))
{
var outputPath = Path.Combine(buildDirectory, alias);
var includeDirs = GetIncludeDirectories(packageRoot, sourceFullPath);
var stdVersion = ExtractCppStandard(executable.Type);
var compilationResult = await _cppCompilation.CompileFileAsync(
sourceFullPath,
outputPath,
stdVersion,
includeDirs);
if (compilationResult.Success && !string.IsNullOrEmpty(compilationResult.ExecutablePath))
{
_logger.LogInformation("Compiled executable {Alias} -> {Path}", alias, compilationResult.ExecutablePath);
compiled[alias] = compilationResult.ExecutablePath;
}
else
{
_logger.LogWarning("Failed to compile executable {Alias}: {Error}", alias, compilationResult.CompilerOutput);
}
}
else
{
var binaryPath = !string.IsNullOrWhiteSpace(executable.BinaryPath)
? Path.Combine(packageRoot, NormalizeRelativePath(executable.BinaryPath))
: null;
if (!string.IsNullOrEmpty(binaryPath) && File.Exists(binaryPath))
{
_logger.LogInformation("Using prebuilt executable {Alias} at {Path}", alias, binaryPath);
compiled[alias] = binaryPath;
}
else
{
_logger.LogWarning("Unsupported executable type {Type} for {Alias}", executable.Type, alias);
}
}
}
return compiled;
}
private async Task<string?> CompileCheckerForPackageAsync(
PolygonProblemDescriptor descriptor,
string packageRoot,
string buildDirectory)
{
if (descriptor.Checker == null || string.IsNullOrWhiteSpace(descriptor.Checker.SourcePath))
{
_logger.LogInformation("No checker declared in problem.xml");
return null;
}
var sourcePath = Path.Combine(packageRoot, NormalizeRelativePath(descriptor.Checker.SourcePath));
if (!File.Exists(sourcePath))
{
_logger.LogWarning("Checker source not found: {SourcePath}", descriptor.Checker.SourcePath);
return null;
}
var alias = !string.IsNullOrWhiteSpace(descriptor.Checker.CopyPath)
? Path.GetFileNameWithoutExtension(descriptor.Checker.CopyPath)
: Path.GetFileNameWithoutExtension(descriptor.Checker.BinaryPath ?? descriptor.Checker.SourcePath);
if (string.IsNullOrWhiteSpace(alias))
{
alias = "checker";
}
var outputPath = Path.Combine(buildDirectory, alias);
var includeDirs = GetIncludeDirectories(packageRoot, sourcePath);
var stdVersion = ExtractCppStandard(descriptor.Checker.Type);
var result = await _cppCompilation.CompileFileAsync(
sourcePath,
outputPath,
stdVersion,
includeDirs);
if (result.Success && !string.IsNullOrEmpty(result.ExecutablePath))
{
_logger.LogInformation("Checker compiled to {Path}", result.ExecutablePath);
return result.ExecutablePath;
}
_logger.LogWarning("Failed to compile checker: {Error}", result.CompilerOutput);
return null;
}
private async Task<string?> CompileValidatorAsync(
PolygonProblemDescriptor descriptor,
string packageRoot,
string buildDirectory,
IDictionary<string, string> compiledExecutables)
{
var validator = descriptor.Validators.FirstOrDefault();
if (validator == null || string.IsNullOrWhiteSpace(validator.SourcePath))
{
_logger.LogInformation("No validator declared in problem.xml");
return null;
}
var sourcePath = Path.Combine(packageRoot, NormalizeRelativePath(validator.SourcePath));
if (!File.Exists(sourcePath))
{
_logger.LogWarning("Validator source not found: {SourcePath}", validator.SourcePath);
return null;
}
var alias = Path.GetFileNameWithoutExtension(validator.BinaryPath ?? validator.SourcePath);
if (string.IsNullOrWhiteSpace(alias))
{
alias = "validator";
}
if (compiledExecutables.TryGetValue(alias, out var compiledPath) && File.Exists(compiledPath))
{
_logger.LogInformation("Reusing precompiled validator executable at {Path}", compiledPath);
return compiledPath;
}
var outputPath = Path.Combine(buildDirectory, alias);
var includeDirs = GetIncludeDirectories(packageRoot, sourcePath);
var stdVersion = ExtractCppStandard(validator.Type);
var result = await _cppCompilation.CompileFileAsync(
sourcePath,
outputPath,
stdVersion,
includeDirs);
if (result.Success && !string.IsNullOrEmpty(result.ExecutablePath))
{
_logger.LogInformation("Validator compiled to {Path}", result.ExecutablePath);
compiledExecutables[alias] = result.ExecutablePath;
return result.ExecutablePath;
}
_logger.LogWarning("Failed to compile validator: {Error}", result.CompilerOutput);
return null;
}
private async Task GenerateAndValidateTestsAsync(
PolygonProblemDescriptor descriptor,
string packageRoot,
IDictionary<string, string> compiledExecutables,
string? validatorPath)
{
if (descriptor.Tests.Count == 0)
{
_logger.LogInformation("problem.xml does not enumerate tests; skipping generation step");
return;
}
foreach (var test in descriptor.Tests)
{
var inputRelative = FormatPolygonPattern(descriptor.InputPathPattern, test.Index);
var inputFullPath = Path.Combine(packageRoot, NormalizeRelativePath(inputRelative));
if (test.Method is PolygonTestMethod.Generated or PolygonTestMethod.Script)
{
await GenerateTestInputAsync(test, packageRoot, inputFullPath, compiledExecutables);
}
else if (!File.Exists(inputFullPath))
{
_logger.LogWarning("Manual test {Index} expected at {Path} but not found", test.Index, inputRelative);
continue;
}
if (!File.Exists(inputFullPath))
{
throw new InvalidOperationException($"Failed to produce input file for test {test.Index} ({inputRelative})");
}
if (!string.IsNullOrEmpty(validatorPath))
{
await ValidateInputAsync(validatorPath, inputFullPath, test.Index);
}
}
}
private async Task GenerateTestInputAsync(
PolygonTestDefinition test,
string packageRoot,
string inputFullPath,
IDictionary<string, string> compiledExecutables)
{
if (string.IsNullOrWhiteSpace(test.Command))
{
_logger.LogWarning("Test {Index} is marked as generated but has no command", test.Index);
return;
}
var args = SplitCommandLine(test.Command);
if (args.Count == 0)
{
_logger.LogWarning("Failed to parse generator command for test {Index}", test.Index);
return;
}
var generatorAlias = args[0];
if (!compiledExecutables.TryGetValue(generatorAlias, out var generatorPath))
{
_logger.LogWarning("Generator {Generator} not found for test {Index}", generatorAlias, test.Index);
return;
}
Directory.CreateDirectory(Path.GetDirectoryName(inputFullPath)!);
_logger.LogInformation("Generating test {Index} using {Generator} {Arguments}",
test.Index,
generatorAlias,
string.Join(' ', args.Skip(1)));
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = generatorPath,
WorkingDirectory = packageRoot,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
foreach (var argument in args.Skip(1))
{
process.StartInfo.ArgumentList.Add(argument);
}
process.Start();
var stderrTask = process.StandardError.ReadToEndAsync();
await using (var outputStream = File.Create(inputFullPath))
{
await process.StandardOutput.BaseStream.CopyToAsync(outputStream);
}
await process.WaitForExitAsync();
var stderr = await stderrTask;
if (process.ExitCode != 0)
{
throw new InvalidOperationException($"Generator '{generatorAlias}' failed for test {test.Index}: {stderr}");
}
if (!string.IsNullOrWhiteSpace(stderr))
{
_logger.LogDebug("Generator '{Generator}' stderr for test {Index}: {Message}", generatorAlias, test.Index, stderr.Trim());
}
}
private async Task ValidateInputAsync(string validatorPath, string inputFilePath, int testIndex)
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = validatorPath,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
var inputContent = await File.ReadAllTextAsync(inputFilePath);
var normalizedInput = inputContent.Replace("\r\n", "\n").Replace("\r", "\n");
await process.StandardInput.WriteAsync(normalizedInput);
process.StandardInput.Close();
var stdoutTask = process.StandardOutput.ReadToEndAsync();
var stderrTask = process.StandardError.ReadToEndAsync();
await process.WaitForExitAsync();
var stdout = await stdoutTask;
var stderr = await stderrTask;
if (process.ExitCode != 0)
{
var message = string.IsNullOrWhiteSpace(stderr) ? stdout : stderr;
throw new InvalidOperationException($"Validator rejected test {testIndex}: {message?.Trim()}");
}
if (!string.IsNullOrWhiteSpace(stdout))
{
_logger.LogDebug("Validator output for test {Index}: {Message}", testIndex, stdout.Trim());
}
}
private static IEnumerable<string> GetIncludeDirectories(string packageRoot, string sourceFullPath)
{
var sourceDirectory = Path.GetDirectoryName(sourceFullPath);
var filesDirectory = Path.Combine(packageRoot, "files");
return new[] { sourceDirectory, filesDirectory, packageRoot }
.Where(dir => !string.IsNullOrWhiteSpace(dir))
.Select(dir => dir!)
.Where(Directory.Exists)
.Distinct();
}
private static string NormalizeRelativePath(string relativePath)
{
return relativePath
.Replace("\\", Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture))
.Replace("/", Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture));
}
private static string FormatPolygonPattern(string pattern, int index)
{
if (string.IsNullOrWhiteSpace(pattern))
{
return index.ToString(CultureInfo.InvariantCulture);
}
return Regex.Replace(pattern, "%0?(\\d*)d", match =>
{
if (int.TryParse(match.Groups[1].Value, out var width) && width > 0)
{
return index.ToString($"D{width}", CultureInfo.InvariantCulture);
}
return index.ToString(CultureInfo.InvariantCulture);
});
}
private static IReadOnlyList<string> SplitCommandLine(string command)
{
var result = new List<string>();
if (string.IsNullOrWhiteSpace(command))
{
return result;
}
var current = new StringBuilder();
var inQuotes = false;
foreach (var ch in command)
{
if (ch == '"')
{
inQuotes = !inQuotes;
continue;
}
if (char.IsWhiteSpace(ch) && !inQuotes)
{
if (current.Length > 0)
{
result.Add(current.ToString());
current.Clear();
}
}
else
{
current.Append(ch);
}
}
if (current.Length > 0)
{
result.Add(current.ToString());
}
return result;
}
private static bool IsCppAsset(string? type, string sourceFullPath)
{
if (!string.IsNullOrWhiteSpace(type) && type.StartsWith("cpp", StringComparison.OrdinalIgnoreCase))
{
return true;
}
var extension = Path.GetExtension(sourceFullPath);
return extension.Equals(".cpp", StringComparison.OrdinalIgnoreCase) ||
extension.Equals(".cc", StringComparison.OrdinalIgnoreCase) ||
extension.Equals(".cxx", StringComparison.OrdinalIgnoreCase);
}
private static string? ExtractCppStandard(string? type)
{
if (string.IsNullOrWhiteSpace(type))
{
return null;
}
var normalized = type.ToLowerInvariant();
if (normalized.Contains("++26")) return "26";
if (normalized.Contains("++23")) return "23";
if (normalized.Contains("++20")) return "20";
if (normalized.Contains("++17")) return "17";
if (normalized.Contains("++14")) return "14";
if (normalized.Contains("++11")) return "11";
return null;
}
private string? FindCorrespondingOutputFile(string inputFile) private string? FindCorrespondingOutputFile(string inputFile)
{ {
var directory = Path.GetDirectoryName(inputFile)!; var directory = Path.GetDirectoryName(inputFile)!;
@@ -278,14 +756,16 @@ public class PackageParserService : IPackageParserService
try try
{ {
var checkerSource = await File.ReadAllTextAsync(candidate);
var checkerDir = Path.GetDirectoryName(candidate)!; var checkerDir = Path.GetDirectoryName(candidate)!;
var outputPath = Path.Combine(checkerDir, Path.GetFileNameWithoutExtension(candidate));
var includeDirs = GetIncludeDirectories(workingDirectory, candidate);
// Compile checker with C++17 (testlib.h compatible) // Compile checker with inferred standard (default C++17)
var compilationResult = await _cppCompilation.CompileAsync( var compilationResult = await _cppCompilation.CompileFileAsync(
checkerSource, candidate,
checkerDir, outputPath,
"17"); "17",
includeDirs);
if (!compilationResult.Success) if (!compilationResult.Success)
{ {

View File

@@ -1,3 +1,6 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml.Linq; using System.Xml.Linq;
using LiquidCode.Tester.Common.Models; using LiquidCode.Tester.Common.Models;
@@ -73,7 +76,89 @@ public class PolygonProblemXmlParser
descriptor.InputPathPattern = testset.Element("input-path-pattern")?.Value ?? "tests/%02d"; descriptor.InputPathPattern = testset.Element("input-path-pattern")?.Value ?? "tests/%02d";
descriptor.AnswerPathPattern = testset.Element("answer-path-pattern")?.Value ?? "tests/%02d.a"; descriptor.AnswerPathPattern = testset.Element("answer-path-pattern")?.Value ?? "tests/%02d.a";
// Parse solutions to find main solution // Parse detailed test definitions (if present)
var testsElement = testset.Element("tests");
if (testsElement != null)
{
var index = 1;
foreach (var testElement in testsElement.Elements("test"))
{
var methodValue = testElement.Attribute("method")?.Value ?? "manual";
var method = methodValue.ToLowerInvariant() switch
{
"generated" => PolygonTestMethod.Generated,
"manual" => PolygonTestMethod.Manual,
"script" => PolygonTestMethod.Script,
_ => PolygonTestMethod.Unknown
};
double? points = null;
var pointsAttr = testElement.Attribute("points")?.Value;
if (!string.IsNullOrWhiteSpace(pointsAttr) &&
double.TryParse(pointsAttr, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedPoints))
{
points = parsedPoints;
}
var definition = new PolygonTestDefinition
{
Index = index,
Method = method,
Command = testElement.Attribute("cmd")?.Value,
Group = testElement.Attribute("group")?.Value,
IsSample = bool.TryParse(testElement.Attribute("sample")?.Value, out var sample) && sample,
Points = points,
Comment = testElement.Attribute("comment")?.Value
};
descriptor.Tests.Add(definition);
index++;
}
if (descriptor.TestCount == 0)
{
descriptor.TestCount = descriptor.Tests.Count;
}
}
// Parse auxiliary executables defined in <files><executables>
var filesSection = problem.Element("files");
if (filesSection != null)
{
var executablesSection = filesSection.Element("executables");
if (executablesSection != null)
{
foreach (var executableElement in executablesSection.Elements("executable"))
{
var sourceElement = executableElement.Element("source");
if (sourceElement == null)
{
continue;
}
var sourcePath = sourceElement.Attribute("path")?.Value;
if (string.IsNullOrWhiteSpace(sourcePath))
{
continue;
}
var binaryPath = executableElement.Element("binary")?.Attribute("path")?.Value;
var name = !string.IsNullOrWhiteSpace(binaryPath)
? Path.GetFileNameWithoutExtension(binaryPath)
: Path.GetFileNameWithoutExtension(sourcePath);
descriptor.Executables.Add(new PolygonExecutableDescriptor
{
Name = name,
SourcePath = sourcePath,
BinaryPath = binaryPath,
Type = sourceElement.Attribute("type")?.Value
});
}
}
}
// Parse assets: solutions, checker, validators
var assets = problem.Element("assets"); var assets = problem.Element("assets");
if (assets != null) if (assets != null)
{ {
@@ -108,6 +193,44 @@ public class PolygonProblemXmlParser
_logger.LogWarning("No main or accepted solution found in problem.xml"); _logger.LogWarning("No main or accepted solution found in problem.xml");
} }
} }
var checkerElement = assets.Element("checker");
if (checkerElement != null)
{
var checkerSource = checkerElement.Element("source");
if (checkerSource != null)
{
descriptor.Checker = new PolygonCheckerDescriptor
{
SourcePath = checkerSource.Attribute("path")?.Value ?? string.Empty,
Type = checkerSource.Attribute("type")?.Value,
BinaryPath = checkerElement.Element("binary")?.Attribute("path")?.Value,
CopyPath = checkerElement.Element("copy")?.Attribute("path")?.Value
};
}
}
var validatorsSection = assets.Element("validators");
if (validatorsSection != null)
{
foreach (var validatorElement in validatorsSection.Elements("validator"))
{
var validatorSource = validatorElement.Element("source");
if (validatorSource == null)
{
continue;
}
var validator = new PolygonValidatorDescriptor
{
SourcePath = validatorSource.Attribute("path")?.Value ?? string.Empty,
Type = validatorSource.Attribute("type")?.Value,
BinaryPath = validatorElement.Element("binary")?.Attribute("path")?.Value
};
descriptor.Validators.Add(validator);
}
}
} }
_logger.LogInformation( _logger.LogInformation(
@@ -138,4 +261,62 @@ public class PolygonProblemDescriptor
public string AnswerPathPattern { get; set; } = "tests/%02d.a"; public string AnswerPathPattern { get; set; } = "tests/%02d.a";
public string? MainSolutionPath { get; set; } public string? MainSolutionPath { get; set; }
public string? MainSolutionType { get; set; } public string? MainSolutionType { get; set; }
public List<PolygonTestDefinition> Tests { get; } = new();
public List<PolygonExecutableDescriptor> Executables { get; } = new();
public PolygonCheckerDescriptor? Checker { get; set; }
public List<PolygonValidatorDescriptor> Validators { get; } = new();
}
/// <summary>
/// Represents a single test entry defined in problem.xml
/// </summary>
public class PolygonTestDefinition
{
public int Index { get; set; }
public PolygonTestMethod Method { get; set; } = PolygonTestMethod.Manual;
public string? Command { get; set; }
public string? Group { get; set; }
public bool IsSample { get; set; }
public double? Points { get; set; }
public string? Comment { get; set; }
}
public enum PolygonTestMethod
{
Manual,
Generated,
Script,
Unknown
}
/// <summary>
/// Represents additional executables (generators, validators, printers) declared in problem.xml
/// </summary>
public class PolygonExecutableDescriptor
{
public string Name { get; set; } = string.Empty;
public string SourcePath { get; set; } = string.Empty;
public string? BinaryPath { get; set; }
public string? Type { get; set; }
}
/// <summary>
/// Represents checker information declared in problem.xml
/// </summary>
public class PolygonCheckerDescriptor
{
public string SourcePath { get; set; } = string.Empty;
public string? BinaryPath { get; set; }
public string? CopyPath { get; set; }
public string? Type { get; set; }
}
/// <summary>
/// Represents validator information declared in problem.xml
/// </summary>
public class PolygonValidatorDescriptor
{
public string SourcePath { get; set; } = string.Empty;
public string? BinaryPath { get; set; }
public string? Type { get; set; }
} }

View File

@@ -64,7 +64,7 @@ public class TestingService : ITestingService
_logger.LogError("No test cases found in package for submit {SubmitId}", request.Id); _logger.LogError("No test cases found in package for submit {SubmitId}", request.Id);
await SendStatusAsync(request, State.Done, ErrorCode.UnknownError, await SendStatusAsync(request, State.Done, ErrorCode.UnknownError,
"No test cases found in package", 0, 0); "No test cases found in package", 0, 0);
CleanupWorkingDirectory(package.WorkingDirectory); CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
return; return;
} }
@@ -113,7 +113,7 @@ public class TestingService : ITestingService
_logger.LogWarning("Time limit exceeded on test {TestNumber}", testCase.Number); _logger.LogWarning("Time limit exceeded on test {TestNumber}", testCase.Number);
await SendStatusAsync(request, State.Done, ErrorCode.TimeLimitError, await SendStatusAsync(request, State.Done, ErrorCode.TimeLimitError,
$"Time limit exceeded on test {testCase.Number}", testCase.Number, package.TestCases.Count); $"Time limit exceeded on test {testCase.Number}", testCase.Number, package.TestCases.Count);
CleanupWorkingDirectory(package.WorkingDirectory); CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
return; return;
} }
@@ -122,7 +122,7 @@ public class TestingService : ITestingService
_logger.LogWarning("Memory limit exceeded on test {TestNumber}", testCase.Number); _logger.LogWarning("Memory limit exceeded on test {TestNumber}", testCase.Number);
await SendStatusAsync(request, State.Done, ErrorCode.MemoryError, await SendStatusAsync(request, State.Done, ErrorCode.MemoryError,
$"Memory limit exceeded on test {testCase.Number}", testCase.Number, package.TestCases.Count); $"Memory limit exceeded on test {testCase.Number}", testCase.Number, package.TestCases.Count);
CleanupWorkingDirectory(package.WorkingDirectory); CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
return; return;
} }
@@ -131,7 +131,7 @@ public class TestingService : ITestingService
_logger.LogWarning("Runtime error on test {TestNumber}: {Error}", testCase.Number, executionResult.ErrorMessage); _logger.LogWarning("Runtime error on test {TestNumber}: {Error}", testCase.Number, executionResult.ErrorMessage);
await SendStatusAsync(request, State.Done, ErrorCode.RuntimeError, await SendStatusAsync(request, State.Done, ErrorCode.RuntimeError,
$"Runtime error on test {testCase.Number}: {executionResult.ErrorMessage}", testCase.Number, package.TestCases.Count); $"Runtime error on test {testCase.Number}: {executionResult.ErrorMessage}", testCase.Number, package.TestCases.Count);
CleanupWorkingDirectory(package.WorkingDirectory); CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
return; return;
} }
@@ -147,7 +147,7 @@ public class TestingService : ITestingService
_logger.LogWarning("Wrong answer on test {TestNumber}", testCase.Number); _logger.LogWarning("Wrong answer on test {TestNumber}", testCase.Number);
await SendStatusAsync(request, State.Done, ErrorCode.IncorrectAnswer, await SendStatusAsync(request, State.Done, ErrorCode.IncorrectAnswer,
$"Wrong answer on test {testCase.Number}", testCase.Number, package.TestCases.Count); $"Wrong answer on test {testCase.Number}", testCase.Number, package.TestCases.Count);
CleanupWorkingDirectory(package.WorkingDirectory); CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
return; return;
} }
@@ -160,7 +160,7 @@ public class TestingService : ITestingService
"All tests passed", package.TestCases.Count, package.TestCases.Count); "All tests passed", package.TestCases.Count, package.TestCases.Count);
// Cleanup // Cleanup
CleanupWorkingDirectory(package.WorkingDirectory); CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -147,10 +147,10 @@ public class PackageParserServiceTests : IDisposable
// Act // Act
var result = await _service.ParsePackageAsync(zipStream); var result = await _service.ParsePackageAsync(zipStream);
// Assert // Assert
Assert.Equal(2, result.TestCases.Count); // Only test 1 and 3 Assert.Equal(2, result.TestCases.Count); // Only tests with complete I/O pairs
Assert.Equal(1, result.TestCases[0].Number); Assert.Equal(1, result.TestCases[0].Number);
Assert.Equal(3, result.TestCases[1].Number); Assert.Equal(2, result.TestCases[1].Number);
} }
[Fact] [Fact]
@@ -171,9 +171,9 @@ public class PackageParserServiceTests : IDisposable
var result = await _service.ParsePackageAsync(zipStream); var result = await _service.ParsePackageAsync(zipStream);
// Assert // Assert
Assert.Equal(2, result.TestCases.Count); // Only test 1 and 3 Assert.Equal(2, result.TestCases.Count); // Only tests with complete I/O pairs
Assert.Equal(1, result.TestCases[0].Number); Assert.Equal(1, result.TestCases[0].Number);
Assert.Equal(3, result.TestCases[1].Number); Assert.Equal(2, result.TestCases[1].Number);
} }
[Fact] [Fact]
@@ -206,9 +206,11 @@ public class PackageParserServiceTests : IDisposable
foreach (var (fileName, content) in files) foreach (var (fileName, content) in files)
{ {
var entry = archive.CreateEntry(fileName); var entry = archive.CreateEntry(fileName);
using var entryStream = entry.Open(); using (var entryStream = entry.Open())
using var writer = new StreamWriter(entryStream); using (var writer = new StreamWriter(entryStream))
writer.Write(content); {
writer.Write(content);
}
} }
} }

Some files were not shown because too many files have changed in this diff Show More