Штуки
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
@@ -2,7 +2,7 @@ name: Build and Push Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches: [ roman ]
|
||||
|
||||
env:
|
||||
REGISTRY: git.nullptr.top
|
||||
@@ -16,10 +16,10 @@ jobs:
|
||||
include:
|
||||
- service: gateway
|
||||
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
|
||||
dockerfile: src/LiquidCode.Tester.Worker/Dockerfile
|
||||
image: git.nullptr.top/liquidcode/liquidcode-tester-worker
|
||||
image: git.nullptr.top/liquidcode/liquidcode-tester-worker-roman
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
57
exam-queue-17/check.cpp
Normal 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
108
exam-queue-17/doall.bat
Normal 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
@@ -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 ""
|
||||
|
||||
57
exam-queue-17/files/check.cpp
Normal 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
@@ -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
280
exam-queue-17/files/gen1.cpp
Normal 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;
|
||||
BIN
exam-queue-17/files/gen1.exe
Normal file
276
exam-queue-17/files/gen2.cpp
Normal 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;
|
||||
BIN
exam-queue-17/files/gen2.exe
Normal file
788
exam-queue-17/files/olymp.sty
Normal 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&%
|
||||
\else%
|
||||
\kw@InputFileName & \texttt{#2} \\
|
||||
\fi\fi%
|
||||
\ifdefined\NoOutputFileName\else%
|
||||
\ifx&%
|
||||
\else%
|
||||
\kw@OutputFileName & \texttt{#3} \\
|
||||
\fi\fi%
|
||||
\ifdefined\NoTimeLimit\else%
|
||||
\ifx&%
|
||||
\else%
|
||||
\kw@TimeLimit & #4 \\
|
||||
\fi\fi%
|
||||
\ifdefined\NoMemoryLimit\else%
|
||||
\ifx&%
|
||||
\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
|
||||
86
exam-queue-17/files/print.cpp
Normal 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()];
|
||||
}
|
||||
}
|
||||
BIN
exam-queue-17/files/print.exe
Normal file
79
exam-queue-17/files/problem.tex
Normal 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}
|
||||
|
||||
53
exam-queue-17/files/statements.ftl
Normal 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}
|
||||
6203
exam-queue-17/files/testlib.h
Normal file
8
exam-queue-17/files/tests/validator-tests/01
Normal 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
|
||||
3
exam-queue-17/files/tests/validator-tests/02
Normal file
@@ -0,0 +1,3 @@
|
||||
1 1
|
||||
1
|
||||
1 1 1
|
||||
3
exam-queue-17/files/tests/validator-tests/03
Normal file
@@ -0,0 +1,3 @@
|
||||
1 1
|
||||
1
|
||||
2 1
|
||||
4
exam-queue-17/files/tests/validator-tests/04
Normal file
@@ -0,0 +1,4 @@
|
||||
2 2
|
||||
1 2
|
||||
1 3 2
|
||||
3 4
|
||||
BIN
exam-queue-17/files/towin.exe
Normal file
11
exam-queue-17/files/tutorial.tex
Normal 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}
|
||||
52
exam-queue-17/files/val.cpp
Normal 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
168
exam-queue-17/problem.xml
Normal 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>
|
||||
19
exam-queue-17/scripts/gen-answer.bat
Normal 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
|
||||
35
exam-queue-17/scripts/gen-answer.sh
Normal 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
|
||||
22
exam-queue-17/scripts/gen-input-via-file.bat
Normal 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
|
||||
50
exam-queue-17/scripts/gen-input-via-file.sh
Normal 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
|
||||
70
exam-queue-17/scripts/gen-input-via-files.bat
Normal 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
|
||||
65
exam-queue-17/scripts/gen-input-via-files.sh
Normal 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
|
||||
10
exam-queue-17/scripts/gen-input-via-stdout.bat
Normal 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
|
||||
29
exam-queue-17/scripts/gen-input-via-stdout.sh
Normal 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
|
||||
4
exam-queue-17/scripts/run-checker-tests.bat
Normal 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
|
||||
5
exam-queue-17/scripts/run-checker-tests.sh
Normal 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"
|
||||
36
exam-queue-17/scripts/run-validator-tests.bat
Normal 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
|
||||
37
exam-queue-17/scripts/run-validator-tests.sh
Normal 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"
|
||||
62
exam-queue-17/solutions/nyatl_ok.cpp
Normal 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;
|
||||
}
|
||||
4
exam-queue-17/solutions/nyatl_ok.cpp.desc
Normal file
@@ -0,0 +1,4 @@
|
||||
File name: nyatl_ok.cpp
|
||||
Tag: ACCEPTED
|
||||
Author: Nyatl
|
||||
Change time: Mon Apr 07 21:16:54 MSK 2025
|
||||
BIN
exam-queue-17/solutions/nyatl_ok.exe
Normal file
54
exam-queue-17/solutions/valavshonok_OK.cpp
Normal 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();
|
||||
}
|
||||
4
exam-queue-17/solutions/valavshonok_OK.cpp.desc
Normal file
@@ -0,0 +1,4 @@
|
||||
File name: valavshonok_OK.cpp
|
||||
Tag: MAIN
|
||||
Author: valavshonok
|
||||
Change time: Tue Apr 01 00:12:51 MSK 2025
|
||||
BIN
exam-queue-17/solutions/valavshonok_OK.exe
Normal file
8
exam-queue-17/statement-sections/russian/example.01
Normal 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
|
||||
2
exam-queue-17/statement-sections/russian/example.01.a
Normal file
@@ -0,0 +1,2 @@
|
||||
9
|
||||
2 8 4 5 6 7 3 9 10
|
||||
13
exam-queue-17/statement-sections/russian/input.tex
Normal 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$ стоит в очереди.
|
||||
16
exam-queue-17/statement-sections/russian/legend.tex
Normal file
@@ -0,0 +1,16 @@
|
||||
В честь юбилея ректорат ЮФУ решил запустить акцию <<Сто и десять кексов>>. В каждом корпусе университета открылась лавка с кексами, в которой каждый студент может получить бесплатные кексы.
|
||||
|
||||
Не прошло и пары минут после открытия, как к лавкам набежали студенты и образовалось много очередей. Но самая большая очередь образовалась в главном корпусе ЮФУ. Изначально в этой очереди стояло $n$ студентов, но потом в течение следующих $m$ минут какие-то студенты приходили и вставали в очередь, а какие-то уходили.
|
||||
|
||||
За каждым студентом закреплен номер его зачетной книжки, будем называть это число номером студента. У каждого студента будет уникальный номер, по которому можно однозначно его идентифицировать. Будем считать, что каждую минуту происходило одно из следующих событий:
|
||||
|
||||
\begin{enumerate}
|
||||
\item Студент с номером $x$ пришел и встал перед студентом с номером $y$;
|
||||
\item Студент с номером $x$ пришел и встал в конец очереди;
|
||||
\item Студент с номером $x$ ушел из очереди; возможно, он потом вернется.
|
||||
\end{enumerate}
|
||||
|
||||
Аналитикам стало интересно, а какой будет очередь после $m$ минут?
|
||||
|
||||
Помогите им и сообщите конечное состояние очереди.
|
||||
|
||||
1
exam-queue-17/statement-sections/russian/name.tex
Normal file
@@ -0,0 +1 @@
|
||||
Очередь за кексами
|
||||
31
exam-queue-17/statement-sections/russian/notes.tex
Normal 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}
|
||||
BIN
exam-queue-17/statement-sections/russian/o1.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
exam-queue-17/statement-sections/russian/o2.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
exam-queue-17/statement-sections/russian/o3.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
exam-queue-17/statement-sections/russian/o4.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
exam-queue-17/statement-sections/russian/o5.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
exam-queue-17/statement-sections/russian/o6.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
exam-queue-17/statement-sections/russian/o7.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
exam-queue-17/statement-sections/russian/o8.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
3
exam-queue-17/statement-sections/russian/output.tex
Normal file
@@ -0,0 +1,3 @@
|
||||
В первой строке выведите одно число $|a|$~--- длину очереди после выполнения всех запросов изменения.
|
||||
|
||||
В следующей строке выведите $|a|$ чисел $a_1, a_2, \cdots , a_{|a|}$, где $a_i$~--- номер студента, который стоит на $i$-й позиции в очереди.
|
||||
15
exam-queue-17/statement-sections/russian/tutorial.tex
Normal file
@@ -0,0 +1,15 @@
|
||||
Давайте просто промоделируем все действия.
|
||||
|
||||
Заведем список элементов, а также сохраним по ключу $x$ указатель на элемент списка. Мы можем это сделать, так как все элементы различны. Например, в С++ можно просто завести коллекцию list<int>, а также map<int, list<int>::iterator> или реализовать свой список.
|
||||
|
||||
Теперь мы можем легко обрабатывать все запросы, а в конце просто выведем весь список.
|
||||
|
||||
Запрос 1-го типа можно обработать так: просто берем по ключу указатель на нужный элемент и вставляем перед ним другой элемент, останется только по ключу $x$ записать указатель на новый элемент.
|
||||
|
||||
Запрос 2-го типа~--- просто добавить в список элемент в конец и сохранить на него указатель.
|
||||
|
||||
Запрос 3-го типа~--- удаляем из списка элемент по его указателю.
|
||||
|
||||
В конце просто выводим массив.
|
||||
|
||||
Итоговая сложность $O(mlog(n))$
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
318
exam-queue-17/statements/.html/russian/problem-statement.css
Normal 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;
|
||||
}
|
||||
29
exam-queue-17/statements/.html/russian/problem.html
Normal file
17
exam-queue-17/statements/.html/russian/tutorial.html
Normal 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<int>, а также map<int, list<int>::iterator> или реализовать свой список.</P><P>Теперь мы можем легко обрабатывать все запросы, а в конце просто выведем весь список.</P><P>Запрос 1-го типа можно обработать так: просто берем по ключу указатель на нужный элемент и вставляем перед ним другой элемент, останется только по ключу $$$x$$$ записать указатель на новый элемент.</P><P>Запрос 2-го типа — просто добавить в список элемент в конец и сохранить на него указатель.</P><P>Запрос 3-го типа — удаляем из списка элемент по его указателю.</P><P>В конце просто выводим массив.</P><P>Итоговая сложность $$$O(mlog(n))$$$</P></DIV></DIV>
|
||||
|
||||
</BODY></HTML>
|
||||
BIN
exam-queue-17/statements/.pdf/russian/problem.pdf
Normal file
BIN
exam-queue-17/statements/.pdf/russian/tutorial.pdf
Normal file
8
exam-queue-17/statements/russian/example.01
Normal 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
|
||||
2
exam-queue-17/statements/russian/example.01.a
Normal file
@@ -0,0 +1,2 @@
|
||||
9
|
||||
2 8 4 5 6 7 3 9 10
|
||||
8
exam-queue-17/statements/russian/example.01.mu
Normal 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
|
||||
BIN
exam-queue-17/statements/russian/o1.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
exam-queue-17/statements/russian/o2.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
exam-queue-17/statements/russian/o3.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
exam-queue-17/statements/russian/o4.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
exam-queue-17/statements/russian/o5.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
exam-queue-17/statements/russian/o6.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
exam-queue-17/statements/russian/o7.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
exam-queue-17/statements/russian/o8.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
1
exam-queue-17/statements/russian/problem-properties.json
Normal file
81
exam-queue-17/statements/russian/problem.tex
Normal 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}
|
||||
|
||||
19
exam-queue-17/statements/russian/tutorial.tex
Normal 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
@@ -0,0 +1 @@
|
||||
realization
|
||||
8
exam-queue-17/tests/01
Normal 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
@@ -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
@@ -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
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace LiquidCode.Tester.Common.Models;
|
||||
public class ProblemPackage
|
||||
{
|
||||
public string WorkingDirectory { get; set; } = string.Empty;
|
||||
public string? ExtractionRoot { get; set; }
|
||||
public List<TestCase> TestCases { get; set; } = new();
|
||||
public string? CheckerPath { get; set; }
|
||||
public int DefaultTimeLimit { get; set; } = 2000; // milliseconds
|
||||
|
||||
@@ -136,23 +136,37 @@ public class AnswerGenerationService
|
||||
return (null, "");
|
||||
}
|
||||
|
||||
if (solutionType.StartsWith("python."))
|
||||
if (solutionType.StartsWith("python"))
|
||||
{
|
||||
var parts = solutionType.Split('.');
|
||||
var version = parts.Length > 1 ? parts[1] : "3";
|
||||
return ("python", $"3.{version}"); // Map python.3 -> 3.3, python.2 -> 3.2 (approx)
|
||||
var versionPart = solutionType.Replace("python", string.Empty, StringComparison.OrdinalIgnoreCase)
|
||||
.Trim('.', ' ');
|
||||
|
||||
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."))
|
||||
{
|
||||
// cpp.g++17, cpp.g++20, cpp.g++14
|
||||
if (solutionType.Contains("++20"))
|
||||
return ("cpp", "20");
|
||||
if (solutionType.Contains("++17"))
|
||||
return ("cpp", "17");
|
||||
if (solutionType.Contains("++14"))
|
||||
return ("cpp", "14");
|
||||
return ("cpp", "17"); // Default to C++17
|
||||
var standard = ExtractCppStandard(solutionType);
|
||||
return ("cpp", standard);
|
||||
}
|
||||
|
||||
if (solutionType.StartsWith("java"))
|
||||
@@ -178,4 +192,22 @@ public class AnswerGenerationService
|
||||
_logger.LogWarning("Unknown solution type: {Type}", solutionType);
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using LiquidCode.Tester.Worker.Models;
|
||||
|
||||
namespace LiquidCode.Tester.Worker.Services;
|
||||
@@ -23,57 +25,8 @@ public class CppCompilationService : ICompilationService
|
||||
|
||||
try
|
||||
{
|
||||
// Write source code to file
|
||||
await File.WriteAllTextAsync(sourceFilePath, sourceCode);
|
||||
|
||||
// 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
|
||||
};
|
||||
}
|
||||
return await CompileFileAsync(sourceFilePath, executablePath, version);
|
||||
}
|
||||
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))
|
||||
{
|
||||
var compiler = _configuration["Cpp:Compiler"] ?? "g++";
|
||||
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 versionCompiler = _configuration[$"{versionKey}:Compiler"];
|
||||
var versionFlags = _configuration[$"{versionKey}:CompilerFlags"];
|
||||
|
||||
if (!string.IsNullOrEmpty(versionCompiler))
|
||||
{
|
||||
_logger.LogInformation("Using C++ version {Version} configuration", version);
|
||||
return (versionCompiler, versionFlags ?? "-O2 -Wall");
|
||||
}
|
||||
|
||||
// Version not found, use default and log warning
|
||||
_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);
|
||||
}
|
||||
|
||||
var versionKey = $"Cpp:Versions:{version}";
|
||||
var versionCompiler = _configuration[$"{versionKey}:Compiler"];
|
||||
var versionFlagsValue = _configuration[$"{versionKey}:CompilerFlags"];
|
||||
|
||||
if (!string.IsNullOrEmpty(versionCompiler) || !string.IsNullOrEmpty(versionFlagsValue))
|
||||
{
|
||||
var resolvedFlags = !string.IsNullOrEmpty(versionFlagsValue)
|
||||
? SplitFlags(versionFlagsValue)
|
||||
: defaultFlags;
|
||||
|
||||
_logger.LogInformation("Using C++ version {Version} configuration", version);
|
||||
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);
|
||||
}
|
||||
|
||||
_logger.LogWarning("C++ version {Version} not found in configuration, using default", version);
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,12 @@ public class OutputCheckerService : IOutputCheckerService
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using LiquidCode.Tester.Common.Models;
|
||||
|
||||
namespace LiquidCode.Tester.Worker.Services;
|
||||
@@ -35,12 +41,15 @@ public class PackageParserService : IPackageParserService
|
||||
using var archive = new ZipArchive(packageStream, ZipArchiveMode.Read);
|
||||
archive.ExtractToDirectory(workingDirectory);
|
||||
|
||||
// Check if this is a Polygon package (has problem.xml)
|
||||
var problemXmlPath = Path.Combine(workingDirectory, "problem.xml");
|
||||
if (File.Exists(problemXmlPath))
|
||||
// Check if this is a Polygon package (search for problem.xml)
|
||||
var problemXmlPath = Directory.EnumerateFiles(workingDirectory, "problem.xml", SearchOption.AllDirectories)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (!string.IsNullOrEmpty(problemXmlPath))
|
||||
{
|
||||
_logger.LogInformation("Detected Polygon package format (problem.xml found)");
|
||||
return await ParsePolygonPackageAsync(workingDirectory, problemXmlPath);
|
||||
var packageRoot = Path.GetDirectoryName(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)
|
||||
@@ -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);
|
||||
|
||||
if (descriptor == null)
|
||||
{
|
||||
_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
|
||||
{
|
||||
WorkingDirectory = workingDirectory,
|
||||
WorkingDirectory = packageRoot,
|
||||
ExtractionRoot = extractionRoot,
|
||||
DefaultTimeLimit = descriptor.TimeLimitMs,
|
||||
DefaultMemoryLimit = descriptor.MemoryLimitMb
|
||||
};
|
||||
|
||||
// Collect test file paths and check which answers are missing
|
||||
var inputPaths = new List<string>();
|
||||
var answerPaths = new List<string>();
|
||||
var missingAnswerPaths = new List<string>();
|
||||
var missingAnswerInputs = new List<string>();
|
||||
var buildDirectory = Path.Combine(packageRoot, ".lc-build");
|
||||
Directory.CreateDirectory(buildDirectory);
|
||||
|
||||
for (int i = 1; i <= descriptor.TestCount; i++)
|
||||
{
|
||||
var inputPath = Path.Combine(workingDirectory,
|
||||
string.Format(descriptor.InputPathPattern.Replace("%02d", "{0:D2}"), i));
|
||||
var answerPath = Path.Combine(workingDirectory,
|
||||
string.Format(descriptor.AnswerPathPattern.Replace("%02d", "{0:D2}"), i));
|
||||
var compiledExecutables = await CompilePolygonExecutablesAsync(descriptor, packageRoot, buildDirectory);
|
||||
|
||||
if (!File.Exists(inputPath))
|
||||
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)
|
||||
{
|
||||
_logger.LogWarning("Input file not found: {InputPath}", inputPath);
|
||||
_logger.LogWarning("No test definitions discovered in problem.xml; falling back to filesystem scan");
|
||||
return await ParseLegacyPackage(packageRoot, extractionRoot);
|
||||
}
|
||||
|
||||
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 for test {Index}: {RelativePath}", testIndex, inputRelative);
|
||||
continue;
|
||||
}
|
||||
|
||||
inputPaths.Add(inputPath);
|
||||
answerPaths.Add(answerPath);
|
||||
var answerRelative = FormatPolygonPattern(descriptor.AnswerPathPattern, testIndex);
|
||||
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))
|
||||
{
|
||||
missingAnswerPaths.Add(answerPath);
|
||||
missingAnswerInputs.Add(inputPath);
|
||||
missingAnswerPaths.Add(answerPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate missing answer files if we have a main solution
|
||||
if (missingAnswerPaths.Count > 0)
|
||||
{
|
||||
_logger.LogInformation("Found {Count} tests without answer files, attempting to generate them",
|
||||
missingAnswerPaths.Count);
|
||||
_logger.LogInformation("Found {Count} tests without answers, attempting to generate them", missingAnswerPaths.Count);
|
||||
|
||||
var generated = await _answerGenerator.GenerateAnswersAsync(
|
||||
descriptor,
|
||||
workingDirectory,
|
||||
packageRoot,
|
||||
missingAnswerInputs,
|
||||
missingAnswerPaths);
|
||||
|
||||
if (generated)
|
||||
if (!generated)
|
||||
{
|
||||
_logger.LogInformation("Successfully generated answer files");
|
||||
_logger.LogWarning("Failed to generate answer files, affected tests will be skipped");
|
||||
}
|
||||
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
|
||||
for (int i = 0; i < inputPaths.Count; i++)
|
||||
foreach (var (index, inputPath) in inputs.OrderBy(item => item.index))
|
||||
{
|
||||
var inputPath = inputPaths[i];
|
||||
var answerPath = answerPaths[i];
|
||||
if (!answers.TryGetValue(index, out var answerPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
package.TestCases.Add(new TestCase
|
||||
{
|
||||
Number = i + 1,
|
||||
Number = index,
|
||||
InputFilePath = inputPath,
|
||||
OutputFilePath = answerPath,
|
||||
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)
|
||||
{
|
||||
_logger.LogWarning("No test cases with answer files found! Expected format: {InputPattern} -> {AnswerPattern}",
|
||||
descriptor.InputPathPattern, descriptor.AnswerPathPattern);
|
||||
_logger.LogWarning("No test cases with answer files found for Polygon package");
|
||||
}
|
||||
|
||||
_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);
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
private async Task<ProblemPackage> ParseLegacyPackage(string workingDirectory)
|
||||
private async Task<ProblemPackage> ParseLegacyPackage(string workingDirectory, string? extractionRoot = null)
|
||||
{
|
||||
var package = new ProblemPackage
|
||||
{
|
||||
WorkingDirectory = workingDirectory
|
||||
WorkingDirectory = workingDirectory,
|
||||
ExtractionRoot = extractionRoot ?? workingDirectory
|
||||
};
|
||||
|
||||
// Find tests directory
|
||||
@@ -193,7 +230,7 @@ public class PackageParserService : IPackageParserService
|
||||
|
||||
package.TestCases.Add(new TestCase
|
||||
{
|
||||
Number = i + 1,
|
||||
Number = package.TestCases.Count + 1,
|
||||
InputFilePath = inputFile,
|
||||
OutputFilePath = outputFile,
|
||||
TimeLimit = package.DefaultTimeLimit,
|
||||
@@ -213,6 +250,447 @@ public class PackageParserService : IPackageParserService
|
||||
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)
|
||||
{
|
||||
var directory = Path.GetDirectoryName(inputFile)!;
|
||||
@@ -278,14 +756,16 @@ public class PackageParserService : IPackageParserService
|
||||
|
||||
try
|
||||
{
|
||||
var checkerSource = await File.ReadAllTextAsync(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)
|
||||
var compilationResult = await _cppCompilation.CompileAsync(
|
||||
checkerSource,
|
||||
checkerDir,
|
||||
"17");
|
||||
// Compile checker with inferred standard (default C++17)
|
||||
var compilationResult = await _cppCompilation.CompileFileAsync(
|
||||
candidate,
|
||||
outputPath,
|
||||
"17",
|
||||
includeDirs);
|
||||
|
||||
if (!compilationResult.Success)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using LiquidCode.Tester.Common.Models;
|
||||
|
||||
@@ -73,7 +76,89 @@ public class PolygonProblemXmlParser
|
||||
descriptor.InputPathPattern = testset.Element("input-path-pattern")?.Value ?? "tests/%02d";
|
||||
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");
|
||||
if (assets != null)
|
||||
{
|
||||
@@ -108,6 +193,44 @@ public class PolygonProblemXmlParser
|
||||
_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(
|
||||
@@ -138,4 +261,62 @@ public class PolygonProblemDescriptor
|
||||
public string AnswerPathPattern { get; set; } = "tests/%02d.a";
|
||||
public string? MainSolutionPath { 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; }
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class TestingService : ITestingService
|
||||
_logger.LogError("No test cases found in package for submit {SubmitId}", request.Id);
|
||||
await SendStatusAsync(request, State.Done, ErrorCode.UnknownError,
|
||||
"No test cases found in package", 0, 0);
|
||||
CleanupWorkingDirectory(package.WorkingDirectory);
|
||||
CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class TestingService : ITestingService
|
||||
_logger.LogWarning("Time limit exceeded on test {TestNumber}", testCase.Number);
|
||||
await SendStatusAsync(request, State.Done, ErrorCode.TimeLimitError,
|
||||
$"Time limit exceeded on test {testCase.Number}", testCase.Number, package.TestCases.Count);
|
||||
CleanupWorkingDirectory(package.WorkingDirectory);
|
||||
CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ public class TestingService : ITestingService
|
||||
_logger.LogWarning("Memory limit exceeded on test {TestNumber}", testCase.Number);
|
||||
await SendStatusAsync(request, State.Done, ErrorCode.MemoryError,
|
||||
$"Memory limit exceeded on test {testCase.Number}", testCase.Number, package.TestCases.Count);
|
||||
CleanupWorkingDirectory(package.WorkingDirectory);
|
||||
CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public class TestingService : ITestingService
|
||||
_logger.LogWarning("Runtime error on test {TestNumber}: {Error}", testCase.Number, executionResult.ErrorMessage);
|
||||
await SendStatusAsync(request, State.Done, ErrorCode.RuntimeError,
|
||||
$"Runtime error on test {testCase.Number}: {executionResult.ErrorMessage}", testCase.Number, package.TestCases.Count);
|
||||
CleanupWorkingDirectory(package.WorkingDirectory);
|
||||
CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public class TestingService : ITestingService
|
||||
_logger.LogWarning("Wrong answer on test {TestNumber}", testCase.Number);
|
||||
await SendStatusAsync(request, State.Done, ErrorCode.IncorrectAnswer,
|
||||
$"Wrong answer on test {testCase.Number}", testCase.Number, package.TestCases.Count);
|
||||
CleanupWorkingDirectory(package.WorkingDirectory);
|
||||
CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ public class TestingService : ITestingService
|
||||
"All tests passed", package.TestCases.Count, package.TestCases.Count);
|
||||
|
||||
// Cleanup
|
||||
CleanupWorkingDirectory(package.WorkingDirectory);
|
||||
CleanupWorkingDirectory(package.ExtractionRoot ?? package.WorkingDirectory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -148,9 +148,9 @@ public class PackageParserServiceTests : IDisposable
|
||||
var result = await _service.ParsePackageAsync(zipStream);
|
||||
|
||||
// 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(3, result.TestCases[1].Number);
|
||||
Assert.Equal(2, result.TestCases[1].Number);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -171,9 +171,9 @@ public class PackageParserServiceTests : IDisposable
|
||||
var result = await _service.ParsePackageAsync(zipStream);
|
||||
|
||||
// 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(3, result.TestCases[1].Number);
|
||||
Assert.Equal(2, result.TestCases[1].Number);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -206,11 +206,13 @@ public class PackageParserServiceTests : IDisposable
|
||||
foreach (var (fileName, content) in files)
|
||||
{
|
||||
var entry = archive.CreateEntry(fileName);
|
||||
using var entryStream = entry.Open();
|
||||
using var writer = new StreamWriter(entryStream);
|
||||
using (var entryStream = entry.Open())
|
||||
using (var writer = new StreamWriter(entryStream))
|
||||
{
|
||||
writer.Write(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memoryStream.Position = 0;
|
||||
return memoryStream;
|
||||
|
||||