From 9b0bedb5ad16d088df1e4be17320d27346ea32a0 Mon Sep 17 00:00:00 2001 From: arthur Date: Thu, 20 Nov 2025 22:51:48 -0300 Subject: [PATCH] feat: new dp problem formated --- vacations/Makefile | 97 + vacations/input/1 | 2 + vacations/input/10 | 2 + vacations/input/11 | 2 + vacations/input/12 | 2 + vacations/input/13 | 2 + vacations/input/14 | 2 + vacations/input/15 | 2 + vacations/input/16 | 2 + vacations/input/17 | 2 + vacations/input/18 | 2 + vacations/input/19 | 2 + vacations/input/2 | 2 + vacations/input/20 | 2 + vacations/input/21 | 2 + vacations/input/22 | 2 + vacations/input/23 | 2 + vacations/input/24 | 2 + vacations/input/25 | 2 + vacations/input/26 | 2 + vacations/input/27 | 2 + vacations/input/28 | 2 + vacations/input/29 | 2 + vacations/input/3 | 2 + vacations/input/30 | 2 + vacations/input/31 | 2 + vacations/input/32 | 2 + vacations/input/33 | 2 + vacations/input/34 | 2 + vacations/input/35 | 2 + vacations/input/36 | 2 + vacations/input/37 | 2 + vacations/input/38 | 2 + vacations/input/39 | 2 + vacations/input/4 | 2 + vacations/input/40 | 2 + vacations/input/41 | 2 + vacations/input/42 | 2 + vacations/input/43 | 2 + vacations/input/44 | 2 + vacations/input/45 | 2 + vacations/input/46 | 2 + vacations/input/47 | 2 + vacations/input/48 | 2 + vacations/input/49 | 2 + vacations/input/5 | 2 + vacations/input/50 | 2 + vacations/input/51 | 2 + vacations/input/52 | 2 + vacations/input/53 | 2 + vacations/input/54 | 2 + vacations/input/55 | 2 + vacations/input/56 | 2 + vacations/input/57 | 2 + vacations/input/6 | 2 + vacations/input/7 | 2 + vacations/input/8 | 2 + vacations/input/9 | 2 + vacations/maratona.cls | 188 + vacations/output/1 | 1 + vacations/output/10 | 1 + vacations/output/100 | 1 + vacations/output/101 | 1 + vacations/output/102 | 1 + vacations/output/103 | 1 + vacations/output/104 | 1 + vacations/output/105 | 1 + vacations/output/106 | 1 + vacations/output/107 | 1 + vacations/output/11 | 1 + vacations/output/12 | 1 + vacations/output/13 | 1 + vacations/output/14 | 1 + vacations/output/15 | 1 + vacations/output/16 | 1 + vacations/output/17 | 1 + vacations/output/18 | 1 + vacations/output/19 | 1 + vacations/output/2 | 1 + vacations/output/20 | 1 + vacations/output/21 | 1 + vacations/output/22 | 1 + vacations/output/23 | 1 + vacations/output/24 | 1 + vacations/output/25 | 1 + vacations/output/26 | 1 + vacations/output/27 | 1 + vacations/output/28 | 1 + vacations/output/29 | 1 + vacations/output/3 | 1 + vacations/output/30 | 1 + vacations/output/31 | 1 + vacations/output/32 | 1 + vacations/output/33 | 1 + vacations/output/34 | 1 + vacations/output/35 | 1 + vacations/output/36 | 1 + vacations/output/37 | 1 + vacations/output/38 | 1 + vacations/output/39 | 1 + vacations/output/4 | 1 + vacations/output/40 | 1 + vacations/output/41 | 1 + vacations/output/42 | 1 + vacations/output/43 | 1 + vacations/output/44 | 1 + vacations/output/45 | 1 + vacations/output/46 | 1 + vacations/output/47 | 1 + vacations/output/48 | 1 + vacations/output/49 | 1 + vacations/output/5 | 1 + vacations/output/50 | 1 + vacations/output/51 | 1 + vacations/output/52 | 1 + vacations/output/53 | 1 + vacations/output/54 | 1 + vacations/output/55 | 1 + vacations/output/56 | 1 + vacations/output/57 | 1 + vacations/output/58 | 1 + vacations/output/59 | 1 + vacations/output/6 | 1 + vacations/output/60 | 1 + vacations/output/61 | 1 + vacations/output/62 | 1 + vacations/output/63 | 1 + vacations/output/64 | 1 + vacations/output/65 | 1 + vacations/output/66 | 1 + vacations/output/67 | 1 + vacations/output/68 | 1 + vacations/output/69 | 1 + vacations/output/7 | 1 + vacations/output/70 | 1 + vacations/output/71 | 1 + vacations/output/72 | 1 + vacations/output/73 | 1 + vacations/output/74 | 1 + vacations/output/75 | 1 + vacations/output/76 | 1 + vacations/output/77 | 1 + vacations/output/78 | 1 + vacations/output/79 | 1 + vacations/output/8 | 1 + vacations/output/80 | 1 + vacations/output/81 | 1 + vacations/output/82 | 1 + vacations/output/83 | 1 + vacations/output/84 | 1 + vacations/output/85 | 1 + vacations/output/86 | 1 + vacations/output/87 | 1 + vacations/output/88 | 1 + vacations/output/89 | 1 + vacations/output/9 | 1 + vacations/output/90 | 1 + vacations/output/91 | 1 + vacations/output/92 | 1 + vacations/output/93 | 1 + vacations/output/94 | 1 + vacations/output/95 | 1 + vacations/output/96 | 1 + vacations/output/97 | 1 + vacations/output/98 | 1 + vacations/output/99 | 1 + vacations/problem.json | 64 + vacations/src/TLE.cpp | 45 + vacations/src/ac.cpp | 42 + vacations/src/checker.cpp | 19 + vacations/src/generator.cpp | 106 + vacations/src/script.sh | 1 + vacations/src/testlib.h | 5963 +++++++++++++++++++++++++++ vacations/src/validator.cpp | 18 + vacations/statement/description.tex | 5 + vacations/statement/input.tex | 9 + vacations/statement/notes.tex | 5 + vacations/statement/output.tex | 1 + vacations/statement/preamble.tex | 0 vacations/statement/tutorial.tex | 0 vacations/vacations.pdf | Bin 0 -> 87235 bytes vacations/vacations.tex | 47 + 182 files changed, 6831 insertions(+) create mode 100644 vacations/Makefile create mode 100644 vacations/input/1 create mode 100644 vacations/input/10 create mode 100644 vacations/input/11 create mode 100644 vacations/input/12 create mode 100644 vacations/input/13 create mode 100644 vacations/input/14 create mode 100644 vacations/input/15 create mode 100644 vacations/input/16 create mode 100644 vacations/input/17 create mode 100644 vacations/input/18 create mode 100644 vacations/input/19 create mode 100644 vacations/input/2 create mode 100644 vacations/input/20 create mode 100644 vacations/input/21 create mode 100644 vacations/input/22 create mode 100644 vacations/input/23 create mode 100644 vacations/input/24 create mode 100644 vacations/input/25 create mode 100644 vacations/input/26 create mode 100644 vacations/input/27 create mode 100644 vacations/input/28 create mode 100644 vacations/input/29 create mode 100644 vacations/input/3 create mode 100644 vacations/input/30 create mode 100644 vacations/input/31 create mode 100644 vacations/input/32 create mode 100644 vacations/input/33 create mode 100644 vacations/input/34 create mode 100644 vacations/input/35 create mode 100644 vacations/input/36 create mode 100644 vacations/input/37 create mode 100644 vacations/input/38 create mode 100644 vacations/input/39 create mode 100644 vacations/input/4 create mode 100644 vacations/input/40 create mode 100644 vacations/input/41 create mode 100644 vacations/input/42 create mode 100644 vacations/input/43 create mode 100644 vacations/input/44 create mode 100644 vacations/input/45 create mode 100644 vacations/input/46 create mode 100644 vacations/input/47 create mode 100644 vacations/input/48 create mode 100644 vacations/input/49 create mode 100644 vacations/input/5 create mode 100644 vacations/input/50 create mode 100644 vacations/input/51 create mode 100644 vacations/input/52 create mode 100644 vacations/input/53 create mode 100644 vacations/input/54 create mode 100644 vacations/input/55 create mode 100644 vacations/input/56 create mode 100644 vacations/input/57 create mode 100644 vacations/input/6 create mode 100644 vacations/input/7 create mode 100644 vacations/input/8 create mode 100644 vacations/input/9 create mode 100644 vacations/maratona.cls create mode 100644 vacations/output/1 create mode 100644 vacations/output/10 create mode 100644 vacations/output/100 create mode 100644 vacations/output/101 create mode 100644 vacations/output/102 create mode 100644 vacations/output/103 create mode 100644 vacations/output/104 create mode 100644 vacations/output/105 create mode 100644 vacations/output/106 create mode 100644 vacations/output/107 create mode 100644 vacations/output/11 create mode 100644 vacations/output/12 create mode 100644 vacations/output/13 create mode 100644 vacations/output/14 create mode 100644 vacations/output/15 create mode 100644 vacations/output/16 create mode 100644 vacations/output/17 create mode 100644 vacations/output/18 create mode 100644 vacations/output/19 create mode 100644 vacations/output/2 create mode 100644 vacations/output/20 create mode 100644 vacations/output/21 create mode 100644 vacations/output/22 create mode 100644 vacations/output/23 create mode 100644 vacations/output/24 create mode 100644 vacations/output/25 create mode 100644 vacations/output/26 create mode 100644 vacations/output/27 create mode 100644 vacations/output/28 create mode 100644 vacations/output/29 create mode 100644 vacations/output/3 create mode 100644 vacations/output/30 create mode 100644 vacations/output/31 create mode 100644 vacations/output/32 create mode 100644 vacations/output/33 create mode 100644 vacations/output/34 create mode 100644 vacations/output/35 create mode 100644 vacations/output/36 create mode 100644 vacations/output/37 create mode 100644 vacations/output/38 create mode 100644 vacations/output/39 create mode 100644 vacations/output/4 create mode 100644 vacations/output/40 create mode 100644 vacations/output/41 create mode 100644 vacations/output/42 create mode 100644 vacations/output/43 create mode 100644 vacations/output/44 create mode 100644 vacations/output/45 create mode 100644 vacations/output/46 create mode 100644 vacations/output/47 create mode 100644 vacations/output/48 create mode 100644 vacations/output/49 create mode 100644 vacations/output/5 create mode 100644 vacations/output/50 create mode 100644 vacations/output/51 create mode 100644 vacations/output/52 create mode 100644 vacations/output/53 create mode 100644 vacations/output/54 create mode 100644 vacations/output/55 create mode 100644 vacations/output/56 create mode 100644 vacations/output/57 create mode 100644 vacations/output/58 create mode 100644 vacations/output/59 create mode 100644 vacations/output/6 create mode 100644 vacations/output/60 create mode 100644 vacations/output/61 create mode 100644 vacations/output/62 create mode 100644 vacations/output/63 create mode 100644 vacations/output/64 create mode 100644 vacations/output/65 create mode 100644 vacations/output/66 create mode 100644 vacations/output/67 create mode 100644 vacations/output/68 create mode 100644 vacations/output/69 create mode 100644 vacations/output/7 create mode 100644 vacations/output/70 create mode 100644 vacations/output/71 create mode 100644 vacations/output/72 create mode 100644 vacations/output/73 create mode 100644 vacations/output/74 create mode 100644 vacations/output/75 create mode 100644 vacations/output/76 create mode 100644 vacations/output/77 create mode 100644 vacations/output/78 create mode 100644 vacations/output/79 create mode 100644 vacations/output/8 create mode 100644 vacations/output/80 create mode 100644 vacations/output/81 create mode 100644 vacations/output/82 create mode 100644 vacations/output/83 create mode 100644 vacations/output/84 create mode 100644 vacations/output/85 create mode 100644 vacations/output/86 create mode 100644 vacations/output/87 create mode 100644 vacations/output/88 create mode 100644 vacations/output/89 create mode 100644 vacations/output/9 create mode 100644 vacations/output/90 create mode 100644 vacations/output/91 create mode 100644 vacations/output/92 create mode 100644 vacations/output/93 create mode 100644 vacations/output/94 create mode 100644 vacations/output/95 create mode 100644 vacations/output/96 create mode 100644 vacations/output/97 create mode 100644 vacations/output/98 create mode 100644 vacations/output/99 create mode 100644 vacations/problem.json create mode 100644 vacations/src/TLE.cpp create mode 100644 vacations/src/ac.cpp create mode 100644 vacations/src/checker.cpp create mode 100644 vacations/src/generator.cpp create mode 100644 vacations/src/script.sh create mode 100644 vacations/src/testlib.h create mode 100644 vacations/src/validator.cpp create mode 100644 vacations/statement/description.tex create mode 100644 vacations/statement/input.tex create mode 100644 vacations/statement/notes.tex create mode 100644 vacations/statement/output.tex create mode 100644 vacations/statement/preamble.tex create mode 100644 vacations/statement/tutorial.tex create mode 100644 vacations/vacations.pdf create mode 100644 vacations/vacations.tex diff --git a/vacations/Makefile b/vacations/Makefile new file mode 100644 index 0000000..4227f1a --- /dev/null +++ b/vacations/Makefile @@ -0,0 +1,97 @@ +# Normal directories +SRC_DIR := src +BIN_DIR := bin +DBG_DIR := bin/debug + +# Grader directories +GRADER := $(wildcard $(SRC_DIR)/grader.cpp) +GRADER_DIR := $(SRC_DIR)/grader +HANDLER_DIR := $(SRC_DIR)/handler + +GRADER_SRC := $(wildcard $(GRADER_DIR)/*.cpp) +GRADER_BIN := $(patsubst $(GRADER_DIR)/%.cpp, $(BIN_DIR)/%, $(GRADER_SRC)) +GRADER_DBG := $(patsubst $(GRADER_DIR)/%.cpp, $(DBG_DIR)/%, $(GRADER_SRC)) + +# Change CPP source directories if grader is defined +ifdef GRADER + SRC := $(wildcard $(HANDLER_DIR)/*.cpp) + BIN := $(patsubst $(HANDLER_DIR)/%.cpp, $(BIN_DIR)/%, $(SRC)) + DBG := $(patsubst $(HANDLER_DIR)/%.cpp, $(DBG_DIR)/%, $(SRC)) +else + SRC := $(wildcard $(SRC_DIR)/*.cpp) + BIN := $(patsubst $(SRC_DIR)/%.cpp, $(BIN_DIR)/%, $(SRC)) + DBG := $(patsubst $(SRC_DIR)/%.cpp, $(DBG_DIR)/%, $(SRC)) +endif + +SRC_C := $(wildcard $(SRC_DIR)/*.c) +BIN_C := $(patsubst $(SRC_DIR)/%.c, $(BIN_DIR)/%, $(SRC_C)) +DBG_C := $(patsubst $(SRC_DIR)/%.c, $(DBG_DIR)/%, $(SRC_C)) + +SRC_JAVA := $(wildcard $(SRC_DIR)/*.java) +BIN_JAVA := $(patsubst $(SRC_DIR)/%.java, $(BIN_DIR)/%.class, $(SRC_JAVA)) +DBG_JAVA := $(patsubst $(SRC_DIR)/%.java, $(DBG_DIR)/%.class, $(SRC_JAVA)) + +CHECKER := $(wildcard $(SRC_DIR)/checker.cpp) + +C := gcc +CPP := g++ +CXX_FLAGS := -Wall -O2 +DEBUG_FLAGS := -Wall -g +BOCA_FLAGS := -static -DBOCA_SUPPORT + +JV = javac +JV_DEBUG = -g +JV_DIR = -d bin +JV_DBG_DIR = -d bin/debug + +.PHONY: all debug release checker clean + +all: debug release checker + +debug: $(DBG) $(DBG_C) $(DBG_JAVA) $(GRADER_DBG) + +release: $(BIN) $(BIN_C) $(BIN_JAVA) $(GRADER_BIN) + +ifdef CHECKER +checker: $(DBG_DIR)/checker-boca $(BIN_DIR)/checker-boca +endif + +$(BIN): $(BIN_DIR)/% : $(SRC_DIR)/%.cpp | $(BIN_DIR) + $(CPP) $(CXX_FLAGS) $^ -o $@ + +$(DBG): $(DBG_DIR)/% : $(SRC_DIR)/%.cpp | $(DBG_DIR) + $(CPP) $(DEBUG_FLAGS) $^ -o $@ + +$(BIN_C): $(BIN_DIR)/% : $(SRC_DIR)/%.c | $(BIN_DIR) + $(C) $(CXX_FLAGS) $^ -o $@ + +$(DBG_C): $(DBG_DIR)/% : $(SRC_DIR)/%.c | $(DBG_DIR) + $(C) $(DEBUG_FLAGS) $^ -o $@ + +$(BIN_JAVA): $(BIN_DIR)/%.class : $(SRC_DIR)/%.java | $(BIN_DIR) + $(JV) $(JV_DIR) $^ + +$(DBG_JAVA): $(DBG_DIR)/%.class : $(SRC_DIR)/%.java | $(DBG_DIR) + $(JV) $(JV_DEBUG) $(JV_DBG_DIR) $^ + +$(GRADER_BIN): $(BIN_DIR)/% : $(GRADER_DIR)/%.cpp $(GRADER) $(GRADER_DIR)/*.h + $(CPP) $(CXX_FLAGS) $^ -o $@ + +$(GRADER_DBG): $(DBG_DIR)/% : $(GRADER_DIR)/%.cpp $(GRADER) $(GRADER_DIR)/*.h + $(CPP) $(DEBUG_FLAGS) $^ -o $@ + +$(BIN_DIR): + mkdir -p $@ + +$(DBG_DIR): + mkdir -p $@ + +$(BIN_DIR)/checker-boca: $(SRC_DIR)/checker.cpp + $(CPP) $(CXX_FLAGS) $(BOCA_FLAGS) $^ -o $@ + +$(DBG_DIR)/checker-boca: $(SRC_DIR)/checker.cpp + $(CPP) $(DEBUG_FLAGS) $(BOCA_FLAGS) $^ -o $@ + +clean: + @echo Cleaning problem files + rm -rf bin diff --git a/vacations/input/1 b/vacations/input/1 new file mode 100644 index 0000000..0d5cee0 --- /dev/null +++ b/vacations/input/1 @@ -0,0 +1,2 @@ +4 +1 3 2 0 diff --git a/vacations/input/10 b/vacations/input/10 new file mode 100644 index 0000000..cc51802 --- /dev/null +++ b/vacations/input/10 @@ -0,0 +1,2 @@ +14 +3 1 0 2 2 1 3 1 3 0 2 3 3 1 diff --git a/vacations/input/11 b/vacations/input/11 new file mode 100644 index 0000000..2c6ebc9 --- /dev/null +++ b/vacations/input/11 @@ -0,0 +1,2 @@ +16 +3 1 3 0 3 2 0 2 3 3 0 2 0 2 0 1 diff --git a/vacations/input/12 b/vacations/input/12 new file mode 100644 index 0000000..83f42c3 --- /dev/null +++ b/vacations/input/12 @@ -0,0 +1,2 @@ +18 +1 3 2 3 1 0 1 2 0 1 1 1 0 2 2 3 2 0 diff --git a/vacations/input/13 b/vacations/input/13 new file mode 100644 index 0000000..a7b13a9 --- /dev/null +++ b/vacations/input/13 @@ -0,0 +1,2 @@ +5 +2 3 3 1 2 diff --git a/vacations/input/14 b/vacations/input/14 new file mode 100644 index 0000000..d76042f --- /dev/null +++ b/vacations/input/14 @@ -0,0 +1,2 @@ +7 +1 2 0 1 0 3 1 diff --git a/vacations/input/15 b/vacations/input/15 new file mode 100644 index 0000000..7737b7e --- /dev/null +++ b/vacations/input/15 @@ -0,0 +1,2 @@ +30 +0 2 0 1 2 1 3 2 2 1 3 1 2 0 3 3 1 0 1 2 1 1 1 3 1 3 0 1 0 1 diff --git a/vacations/input/16 b/vacations/input/16 new file mode 100644 index 0000000..6134b48 --- /dev/null +++ b/vacations/input/16 @@ -0,0 +1,2 @@ +22 +0 0 3 0 3 3 1 3 2 2 3 0 0 1 3 2 2 0 2 3 2 2 diff --git a/vacations/input/17 b/vacations/input/17 new file mode 100644 index 0000000..ae74824 --- /dev/null +++ b/vacations/input/17 @@ -0,0 +1,2 @@ +12 +3 2 0 1 2 2 3 1 3 2 3 2 diff --git a/vacations/input/18 b/vacations/input/18 new file mode 100644 index 0000000..5f7a3d8 --- /dev/null +++ b/vacations/input/18 @@ -0,0 +1,2 @@ +5 +1 0 0 3 3 diff --git a/vacations/input/19 b/vacations/input/19 new file mode 100644 index 0000000..b68e106 --- /dev/null +++ b/vacations/input/19 @@ -0,0 +1,2 @@ +12 +2 0 0 0 3 0 2 3 1 0 3 2 diff --git a/vacations/input/2 b/vacations/input/2 new file mode 100644 index 0000000..bd5aee5 --- /dev/null +++ b/vacations/input/2 @@ -0,0 +1,2 @@ +7 +1 3 3 2 1 2 3 diff --git a/vacations/input/20 b/vacations/input/20 new file mode 100644 index 0000000..e9063eb --- /dev/null +++ b/vacations/input/20 @@ -0,0 +1,2 @@ +18 +0 1 3 0 0 1 1 2 2 0 2 2 2 1 0 3 1 1 diff --git a/vacations/input/21 b/vacations/input/21 new file mode 100644 index 0000000..834a49a --- /dev/null +++ b/vacations/input/21 @@ -0,0 +1,2 @@ +21 +2 3 1 2 1 1 0 2 1 0 2 2 1 0 2 1 1 1 1 2 0 diff --git a/vacations/input/22 b/vacations/input/22 new file mode 100644 index 0000000..0846391 --- /dev/null +++ b/vacations/input/22 @@ -0,0 +1,2 @@ +48 +0 3 3 0 2 3 0 3 0 1 3 2 0 3 0 2 2 3 3 0 2 1 2 3 0 3 3 2 2 3 0 0 2 0 1 2 1 2 1 0 1 2 1 0 3 3 0 2 diff --git a/vacations/input/23 b/vacations/input/23 new file mode 100644 index 0000000..ec0892c --- /dev/null +++ b/vacations/input/23 @@ -0,0 +1,2 @@ +29 +0 1 2 3 3 1 2 3 3 2 1 0 3 1 1 0 1 0 2 0 0 1 0 3 2 1 1 0 2 diff --git a/vacations/input/24 b/vacations/input/24 new file mode 100644 index 0000000..0a75351 --- /dev/null +++ b/vacations/input/24 @@ -0,0 +1,2 @@ +31 +1 3 0 2 0 1 0 1 0 3 3 2 0 0 2 3 2 0 0 1 2 1 1 1 0 2 1 2 2 3 1 diff --git a/vacations/input/25 b/vacations/input/25 new file mode 100644 index 0000000..f779fd6 --- /dev/null +++ b/vacations/input/25 @@ -0,0 +1,2 @@ +9 +3 2 3 3 2 1 1 2 1 diff --git a/vacations/input/26 b/vacations/input/26 new file mode 100644 index 0000000..3769002 --- /dev/null +++ b/vacations/input/26 @@ -0,0 +1,2 @@ +48 +2 0 2 1 0 2 2 1 3 3 1 3 1 3 3 2 0 0 1 2 3 0 1 1 1 1 2 1 1 0 1 0 0 3 0 3 2 3 1 3 1 2 3 3 0 1 1 0 diff --git a/vacations/input/27 b/vacations/input/27 new file mode 100644 index 0000000..773f64d --- /dev/null +++ b/vacations/input/27 @@ -0,0 +1,2 @@ +45 +0 0 3 1 1 2 2 3 1 2 0 0 3 1 0 2 3 0 2 3 0 0 3 3 3 0 0 3 2 2 2 3 1 3 1 1 0 2 0 0 2 1 3 2 0 diff --git a/vacations/input/28 b/vacations/input/28 new file mode 100644 index 0000000..4ec3ebd --- /dev/null +++ b/vacations/input/28 @@ -0,0 +1,2 @@ +21 +2 2 1 0 3 3 3 1 3 3 0 1 1 1 3 3 2 3 3 0 0 diff --git a/vacations/input/29 b/vacations/input/29 new file mode 100644 index 0000000..85551cc --- /dev/null +++ b/vacations/input/29 @@ -0,0 +1,2 @@ +4 +3 1 0 0 diff --git a/vacations/input/3 b/vacations/input/3 new file mode 100644 index 0000000..2d77785 --- /dev/null +++ b/vacations/input/3 @@ -0,0 +1,2 @@ +2 +2 2 diff --git a/vacations/input/30 b/vacations/input/30 new file mode 100644 index 0000000..ef43168 --- /dev/null +++ b/vacations/input/30 @@ -0,0 +1,2 @@ +40 +3 3 0 2 2 0 2 3 3 1 3 0 2 1 3 3 1 1 2 2 3 0 3 2 1 0 0 0 0 0 0 0 1 1 1 1 0 0 2 3 diff --git a/vacations/input/31 b/vacations/input/31 new file mode 100644 index 0000000..7d26f98 --- /dev/null +++ b/vacations/input/31 @@ -0,0 +1,2 @@ +14 +0 1 1 3 1 2 0 0 1 3 1 2 2 2 diff --git a/vacations/input/32 b/vacations/input/32 new file mode 100644 index 0000000..2d31fa5 --- /dev/null +++ b/vacations/input/32 @@ -0,0 +1,2 @@ +36 +1 2 2 3 2 2 2 1 2 0 1 2 0 2 0 0 3 0 3 0 2 1 0 1 2 3 3 3 0 2 0 0 0 1 0 2 diff --git a/vacations/input/33 b/vacations/input/33 new file mode 100644 index 0000000..19269c0 --- /dev/null +++ b/vacations/input/33 @@ -0,0 +1,2 @@ +24 +1 0 3 2 1 0 0 0 0 2 3 0 2 0 0 1 3 2 0 0 2 2 1 2 diff --git a/vacations/input/34 b/vacations/input/34 new file mode 100644 index 0000000..6e6293a --- /dev/null +++ b/vacations/input/34 @@ -0,0 +1,2 @@ +100 +2 3 3 1 1 3 3 2 2 3 1 2 3 3 0 0 3 2 0 1 1 2 3 2 3 0 1 2 0 1 2 2 2 0 0 3 1 1 3 3 2 3 3 1 1 3 2 1 3 3 3 1 0 0 0 2 3 1 1 3 1 1 2 1 2 1 1 2 0 0 2 2 2 1 1 1 2 0 0 3 3 1 2 2 3 0 1 0 2 3 0 2 2 0 2 2 1 0 1 2 diff --git a/vacations/input/35 b/vacations/input/35 new file mode 100644 index 0000000..878e735 --- /dev/null +++ b/vacations/input/35 @@ -0,0 +1,2 @@ +36 +0 0 2 1 0 2 2 2 3 1 2 2 1 0 1 2 1 0 3 1 3 3 2 2 3 0 0 0 0 1 3 0 2 1 0 3 diff --git a/vacations/input/36 b/vacations/input/36 new file mode 100644 index 0000000..6aabdff --- /dev/null +++ b/vacations/input/36 @@ -0,0 +1,2 @@ +37 +3 1 2 3 1 3 0 1 1 0 3 3 3 3 3 0 1 3 1 0 2 3 1 1 0 1 1 1 2 3 0 2 2 1 1 0 0 diff --git a/vacations/input/37 b/vacations/input/37 new file mode 100644 index 0000000..b916f0c --- /dev/null +++ b/vacations/input/37 @@ -0,0 +1,2 @@ +6 +1 3 1 2 0 3 diff --git a/vacations/input/38 b/vacations/input/38 new file mode 100644 index 0000000..8631831 --- /dev/null +++ b/vacations/input/38 @@ -0,0 +1,2 @@ +59 +0 0 2 2 1 0 1 3 0 2 0 2 1 2 1 2 2 1 1 1 2 3 3 3 0 1 3 1 0 0 0 3 2 0 2 3 1 1 1 0 2 2 0 3 2 1 3 1 0 1 1 3 0 0 3 1 1 1 3 diff --git a/vacations/input/39 b/vacations/input/39 new file mode 100644 index 0000000..dbe7e08 --- /dev/null +++ b/vacations/input/39 @@ -0,0 +1,2 @@ +9 +0 3 2 0 2 0 2 2 2 diff --git a/vacations/input/4 b/vacations/input/4 new file mode 100644 index 0000000..b541ffb --- /dev/null +++ b/vacations/input/4 @@ -0,0 +1,2 @@ +5 +0 0 0 0 0 diff --git a/vacations/input/40 b/vacations/input/40 new file mode 100644 index 0000000..650d85e --- /dev/null +++ b/vacations/input/40 @@ -0,0 +1,2 @@ +91 +1 3 1 2 1 3 0 0 1 0 2 0 2 0 3 1 0 2 2 0 1 2 0 1 1 0 3 3 0 1 0 3 3 2 1 0 3 3 0 2 1 1 2 3 1 1 0 1 2 3 1 2 3 3 2 3 2 3 1 1 0 3 0 2 1 0 3 2 2 2 0 3 2 2 2 0 1 1 2 0 1 2 1 0 0 0 2 0 3 2 1 diff --git a/vacations/input/41 b/vacations/input/41 new file mode 100644 index 0000000..2875d48 --- /dev/null +++ b/vacations/input/41 @@ -0,0 +1,2 @@ +71 +0 1 0 1 2 1 2 3 3 0 2 0 1 2 1 1 2 0 2 2 2 1 3 1 1 0 2 0 2 3 2 3 2 1 2 3 3 2 2 0 1 2 2 0 0 2 0 2 0 2 2 0 0 3 2 1 0 3 0 3 3 0 0 2 1 1 1 0 2 2 3 diff --git a/vacations/input/42 b/vacations/input/42 new file mode 100644 index 0000000..6391354 --- /dev/null +++ b/vacations/input/42 @@ -0,0 +1,2 @@ +76 +0 2 2 3 1 0 1 1 0 3 0 1 3 1 2 0 0 1 3 2 0 1 3 1 1 0 2 1 1 1 2 2 1 2 0 1 0 2 2 0 1 0 3 1 0 2 3 3 1 3 0 0 3 0 3 0 2 3 3 0 3 3 1 1 3 2 3 3 3 3 2 2 3 0 3 0 diff --git a/vacations/input/43 b/vacations/input/43 new file mode 100644 index 0000000..cc5e933 --- /dev/null +++ b/vacations/input/43 @@ -0,0 +1,2 @@ +43 +1 1 0 3 3 1 1 3 3 1 1 1 0 2 3 1 1 2 2 2 0 3 0 0 0 2 3 2 0 1 3 1 1 1 1 3 0 0 2 0 1 0 2 diff --git a/vacations/input/44 b/vacations/input/44 new file mode 100644 index 0000000..347ed51 --- /dev/null +++ b/vacations/input/44 @@ -0,0 +1,2 @@ +10 +1 2 2 0 1 1 3 2 2 1 diff --git a/vacations/input/45 b/vacations/input/45 new file mode 100644 index 0000000..f93a344 --- /dev/null +++ b/vacations/input/45 @@ -0,0 +1,2 @@ +21 +2 3 0 3 3 2 0 0 1 3 2 2 0 3 0 1 3 2 0 2 2 diff --git a/vacations/input/46 b/vacations/input/46 new file mode 100644 index 0000000..40c9b20 --- /dev/null +++ b/vacations/input/46 @@ -0,0 +1,2 @@ +23 +0 3 1 2 0 2 0 3 3 3 1 2 3 3 0 0 0 2 2 1 0 1 2 diff --git a/vacations/input/47 b/vacations/input/47 new file mode 100644 index 0000000..ba79eba --- /dev/null +++ b/vacations/input/47 @@ -0,0 +1,2 @@ +63 +2 0 3 3 2 2 1 1 3 0 3 1 1 2 2 3 3 1 1 0 3 2 0 1 1 2 1 2 0 0 1 3 0 2 0 2 1 0 1 0 3 0 3 3 3 0 2 3 1 3 3 2 0 0 0 1 3 2 1 2 0 2 2 diff --git a/vacations/input/48 b/vacations/input/48 new file mode 100644 index 0000000..2ceee73 --- /dev/null +++ b/vacations/input/48 @@ -0,0 +1,2 @@ +53 +0 0 2 1 1 2 2 2 0 3 3 1 3 2 0 1 3 0 2 2 3 2 1 1 3 0 2 1 2 3 0 1 1 1 2 0 2 3 0 3 2 2 1 2 3 3 2 3 3 1 2 2 3 diff --git a/vacations/input/49 b/vacations/input/49 new file mode 100644 index 0000000..8d9abe0 --- /dev/null +++ b/vacations/input/49 @@ -0,0 +1,2 @@ +7 +0 3 0 3 1 0 1 diff --git a/vacations/input/5 b/vacations/input/5 new file mode 100644 index 0000000..b6ad0ca --- /dev/null +++ b/vacations/input/5 @@ -0,0 +1,2 @@ +5 +3 3 3 3 3 diff --git a/vacations/input/50 b/vacations/input/50 new file mode 100644 index 0000000..5b80cb9 --- /dev/null +++ b/vacations/input/50 @@ -0,0 +1,2 @@ +45 +3 0 0 0 3 1 1 3 3 3 2 3 0 3 1 3 2 0 0 0 3 1 0 2 0 2 3 0 1 2 2 3 3 3 3 0 1 2 0 3 0 3 3 0 1 diff --git a/vacations/input/51 b/vacations/input/51 new file mode 100644 index 0000000..c396449 --- /dev/null +++ b/vacations/input/51 @@ -0,0 +1,2 @@ +59 +0 2 3 1 2 3 2 0 2 2 2 3 2 1 2 3 0 2 1 1 0 2 0 2 1 2 2 2 1 1 2 1 0 1 1 1 1 1 2 1 2 0 0 3 3 0 0 0 2 1 0 3 2 0 1 1 0 0 1 diff --git a/vacations/input/52 b/vacations/input/52 new file mode 100644 index 0000000..07eddfc --- /dev/null +++ b/vacations/input/52 @@ -0,0 +1,2 @@ +93 +0 0 1 3 2 3 1 0 2 2 3 2 3 2 0 3 1 0 3 3 3 2 0 3 2 1 2 0 3 1 2 1 1 3 1 0 1 0 2 2 0 3 2 2 1 3 1 2 0 2 0 2 0 3 1 3 2 1 1 2 0 2 3 2 3 1 3 1 1 0 0 3 3 3 1 2 0 3 0 0 1 3 2 0 3 3 0 2 0 0 2 3 2 diff --git a/vacations/input/53 b/vacations/input/53 new file mode 100644 index 0000000..413b7fc --- /dev/null +++ b/vacations/input/53 @@ -0,0 +1,2 @@ +23 +2 2 2 2 1 1 2 0 3 0 0 2 2 0 1 2 3 2 3 0 1 2 3 diff --git a/vacations/input/54 b/vacations/input/54 new file mode 100644 index 0000000..039fefc --- /dev/null +++ b/vacations/input/54 @@ -0,0 +1,2 @@ +39 +0 1 3 3 3 3 1 1 2 1 2 3 1 0 1 3 3 0 2 0 0 2 3 1 0 3 2 0 2 3 0 1 1 2 3 1 2 2 2 diff --git a/vacations/input/55 b/vacations/input/55 new file mode 100644 index 0000000..609e204 --- /dev/null +++ b/vacations/input/55 @@ -0,0 +1,2 @@ +88 +0 3 0 2 2 2 1 1 1 3 1 2 0 3 2 3 2 3 2 0 3 3 2 3 0 3 1 2 2 1 3 1 3 1 3 1 1 0 2 2 0 2 1 2 1 0 2 0 1 2 3 2 2 2 2 0 3 3 0 2 3 3 2 2 3 2 3 3 0 1 0 3 1 3 2 2 3 3 0 1 2 1 2 0 3 0 3 0 diff --git a/vacations/input/56 b/vacations/input/56 new file mode 100644 index 0000000..af4638d --- /dev/null +++ b/vacations/input/56 @@ -0,0 +1,2 @@ +100 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/vacations/input/57 b/vacations/input/57 new file mode 100644 index 0000000..4ab7b54 --- /dev/null +++ b/vacations/input/57 @@ -0,0 +1,2 @@ +100 +3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 diff --git a/vacations/input/6 b/vacations/input/6 new file mode 100644 index 0000000..65cd4f5 --- /dev/null +++ b/vacations/input/6 @@ -0,0 +1,2 @@ +2 +2 1 diff --git a/vacations/input/7 b/vacations/input/7 new file mode 100644 index 0000000..6247317 --- /dev/null +++ b/vacations/input/7 @@ -0,0 +1,2 @@ +22 +3 0 2 0 0 1 2 0 1 3 0 3 3 1 3 0 0 2 1 2 2 1 diff --git a/vacations/input/8 b/vacations/input/8 new file mode 100644 index 0000000..1274866 --- /dev/null +++ b/vacations/input/8 @@ -0,0 +1,2 @@ +20 +3 3 3 3 2 0 0 2 1 2 3 2 3 0 1 1 3 3 2 0 diff --git a/vacations/input/9 b/vacations/input/9 new file mode 100644 index 0000000..26479a2 --- /dev/null +++ b/vacations/input/9 @@ -0,0 +1,2 @@ +19 +1 0 2 2 2 1 2 3 2 1 0 3 0 2 0 3 0 2 1 diff --git a/vacations/maratona.cls b/vacations/maratona.cls new file mode 100644 index 0000000..e11d53d --- /dev/null +++ b/vacations/maratona.cls @@ -0,0 +1,188 @@ +\ProvidesPackage{maratona} +\LoadClass[11pt]{article} + +% remove page numbers +\pagenumbering{gobble} + +\RequirePackage{fancyhdr} + +\RequirePackage{tabularx,colortbl} + +%\RequirePackage{arial} +\RequirePackage{ifpdf} +\RequirePackage[T1]{fontenc} +\RequirePackage[utf8]{inputenc} +\RequirePackage[portuguese]{babel} +\RequirePackage{graphics} +\RequirePackage{graphicx} +\RequirePackage{amssymb,amsmath,wrapfig} +\RequirePackage{xcolor,colortbl} +\RequirePackage{xcolor} +\RequirePackage{ifthen} +\oddsidemargin 0cm +\evensidemargin -2cm +\topmargin -1cm +\textwidth 16cm +\textheight 23cm + +\ifpdf +\RequirePackage[pdftex]{hyperref} +\else +\RequirePackage[hypertex]{hyperref} +\fi + + +\newcommand{\var}[1]{\ensuremath{{#1}}} + + +\hypersetup{ + letterpaper, + colorlinks=true, + linkcolor=blue, + urlcolor=blue, + pdfpagemode=none, + pdftitle={IV Maratona de Programação do IFB \today}, + pdfauthor={}, + pdfsubject={Caderno de problemas da IV Maratona de Programação do IFB }, + pdfkeywords={maratona, programação, IFB} +} + + + +\DeclareGraphicsExtensions{png} + +\lhead{DS Contest Tools} +\pagestyle{fancy} + +% Capa +\newenvironment{Maratona}[3] +{ + \begin{titlepage} + \begin{center} + + \vspace{1cm} + \Large{\textbf{#1}} \\ + \vspace{1cm} + {\textbf{Caderno de Problemas}} \\ + \vspace{1cm} + \begin{small} + \textsl{#2} + \end{small} \\ + \begin{figure}[htp] + \begin{center} + \includegraphics[scale=1]{logos/logo-maratona.png} + \end{center} + \end{figure} + {(Este caderno contém {#3} problemas)} \\ + \vspace{1cm} + } + { + \vfill + \begin{small} + {QNM 40, Área Especial nº 01, + Taguatinga/DF, 72146-000 , + Brasil } \\ + {Telefone (61) 2103-2200 \\http://www.ifb.edu.br/taguatinga} \\ + \end{small} + \end{center} + \end{titlepage} +} + +\newcommand{\Organizacao}[2]{ + {\small \vfill + \begin{center} + + \textbf{Comissão Organizadora:} \\ + {#1} \\ + \bigskip + \textbf{Apoio:}\\ + {#2} + \end{center} + } + \vfill +} + + +% Problema +\newcounter{problem} +\newenvironment{Problema}[4]{ + \stepcounter{problem} + \newpage + \begin{center} + \Large{\ifthenelse{\equal{#1}{}}{\textbf{{#2}}}{\textbf{Problema {#1} -- {#2} }}}{\\\footnotesize \textbf{Limite de tempo: {#3}s}}{\\[-0.1cm]\footnotesize \textbf{Limite de memória: {#4}MB}} + \end{center} +} + +\newcounter{problemAutor} +\newenvironment{ProblemaAutor}[5]{ + \stepcounter{problemAutor} + \newpage + \begin{center} + \Large{\ifthenelse{\equal{#1}{}}{\textbf{{#2}}}{\textbf{Problema {#1} -- {#2} }}}{\\\footnotesize \textbf{Limite de tempo: {#3}s}}{\\[-0.1cm]\footnotesize \textbf{Limite de memória: {#4}MB\\}}{ + \footnotesize Autor: {#5} + } + \end{center} +} + + +% Código-fonte +\newcommand{\codigofonte}[1]{Nome do arquivo fonte: {#1}} + +% Entrada +\newcommand{\Entrada}{ + \bigskip + \begin{large} + \textbf{Entrada} \\ + \end{large} +} + +% Saida +\newcommand{\Saida}{ + \bigskip + \begin{large} + \textbf{Saída} \\ + \end{large} +} + +\newcommand{\Interacao}{ + \bigskip + \begin{large} + \textbf{Interação} \\ + \end{large} +} + +\newcommand{\Notas}{ + \bigskip + \begin{large} + \textbf{Notas} \\ + \end{large} +} + +% Exemplo +\newenvironment{Exemplo} +{ + + \tabularx{\textwidth}{XX} + % {@{\extracolsep{\fill}}|l|l|} + % {|l|l@{\extracolsep{\fill}|}} + \hline + Entrada & Saída \\\hline +} +{ + \hline + \endtabularx +} + +% Exemplo de Entrada +\newenvironment{ExemploEntrada} +{ + \bigskip + \begin{large} + \textbf{Exemplo} \\ + \end{large} +} +{ +} + +% Sample Output + diff --git a/vacations/output/1 b/vacations/output/1 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/vacations/output/1 @@ -0,0 +1 @@ +2 diff --git a/vacations/output/10 b/vacations/output/10 new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/vacations/output/10 @@ -0,0 +1 @@ +3 diff --git a/vacations/output/100 b/vacations/output/100 new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/vacations/output/100 @@ -0,0 +1 @@ +20 diff --git a/vacations/output/101 b/vacations/output/101 new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/vacations/output/101 @@ -0,0 +1 @@ +4 diff --git a/vacations/output/102 b/vacations/output/102 new file mode 100644 index 0000000..f04c001 --- /dev/null +++ b/vacations/output/102 @@ -0,0 +1 @@ +29 diff --git a/vacations/output/103 b/vacations/output/103 new file mode 100644 index 0000000..f5c8955 --- /dev/null +++ b/vacations/output/103 @@ -0,0 +1 @@ +32 diff --git a/vacations/output/104 b/vacations/output/104 new file mode 100644 index 0000000..7273c0f --- /dev/null +++ b/vacations/output/104 @@ -0,0 +1 @@ +25 diff --git a/vacations/output/105 b/vacations/output/105 new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/vacations/output/105 @@ -0,0 +1 @@ +12 diff --git a/vacations/output/106 b/vacations/output/106 new file mode 100644 index 0000000..29d6383 --- /dev/null +++ b/vacations/output/106 @@ -0,0 +1 @@ +100 diff --git a/vacations/output/107 b/vacations/output/107 new file mode 100644 index 0000000..573541a --- /dev/null +++ b/vacations/output/107 @@ -0,0 +1 @@ +0 diff --git a/vacations/output/11 b/vacations/output/11 new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vacations/output/11 @@ -0,0 +1 @@ +5 diff --git a/vacations/output/12 b/vacations/output/12 new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/vacations/output/12 @@ -0,0 +1 @@ +7 diff --git a/vacations/output/13 b/vacations/output/13 new file mode 100644 index 0000000..573541a --- /dev/null +++ b/vacations/output/13 @@ -0,0 +1 @@ +0 diff --git a/vacations/output/14 b/vacations/output/14 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/vacations/output/14 @@ -0,0 +1 @@ +2 diff --git a/vacations/output/15 b/vacations/output/15 new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/vacations/output/15 @@ -0,0 +1 @@ +8 diff --git a/vacations/output/16 b/vacations/output/16 new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/vacations/output/16 @@ -0,0 +1 @@ +9 diff --git a/vacations/output/17 b/vacations/output/17 new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/vacations/output/17 @@ -0,0 +1 @@ +3 diff --git a/vacations/output/18 b/vacations/output/18 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/vacations/output/18 @@ -0,0 +1 @@ +2 diff --git a/vacations/output/19 b/vacations/output/19 new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/vacations/output/19 @@ -0,0 +1 @@ +6 diff --git a/vacations/output/2 b/vacations/output/2 new file mode 100644 index 0000000..573541a --- /dev/null +++ b/vacations/output/2 @@ -0,0 +1 @@ +0 diff --git a/vacations/output/20 b/vacations/output/20 new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/vacations/output/20 @@ -0,0 +1 @@ +9 diff --git a/vacations/output/21 b/vacations/output/21 new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/vacations/output/21 @@ -0,0 +1 @@ +9 diff --git a/vacations/output/22 b/vacations/output/22 new file mode 100644 index 0000000..98d9bcb --- /dev/null +++ b/vacations/output/22 @@ -0,0 +1 @@ +17 diff --git a/vacations/output/23 b/vacations/output/23 new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/vacations/output/23 @@ -0,0 +1 @@ +11 diff --git a/vacations/output/24 b/vacations/output/24 new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/vacations/output/24 @@ -0,0 +1 @@ +11 diff --git a/vacations/output/25 b/vacations/output/25 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/vacations/output/25 @@ -0,0 +1 @@ +2 diff --git a/vacations/output/26 b/vacations/output/26 new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/vacations/output/26 @@ -0,0 +1 @@ +18 diff --git a/vacations/output/27 b/vacations/output/27 new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/vacations/output/27 @@ -0,0 +1 @@ +20 diff --git a/vacations/output/28 b/vacations/output/28 new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/vacations/output/28 @@ -0,0 +1 @@ +6 diff --git a/vacations/output/29 b/vacations/output/29 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/vacations/output/29 @@ -0,0 +1 @@ +2 diff --git a/vacations/output/3 b/vacations/output/3 new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/vacations/output/3 @@ -0,0 +1 @@ +1 diff --git a/vacations/output/30 b/vacations/output/30 new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/vacations/output/30 @@ -0,0 +1 @@ +18 diff --git a/vacations/output/31 b/vacations/output/31 new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vacations/output/31 @@ -0,0 +1 @@ +5 diff --git a/vacations/output/32 b/vacations/output/32 new file mode 100644 index 0000000..8351c19 --- /dev/null +++ b/vacations/output/32 @@ -0,0 +1 @@ +14 diff --git a/vacations/output/33 b/vacations/output/33 new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/vacations/output/33 @@ -0,0 +1 @@ +12 diff --git a/vacations/output/34 b/vacations/output/34 new file mode 100644 index 0000000..bb95160 --- /dev/null +++ b/vacations/output/34 @@ -0,0 +1 @@ +33 diff --git a/vacations/output/35 b/vacations/output/35 new file mode 100644 index 0000000..60d3b2f --- /dev/null +++ b/vacations/output/35 @@ -0,0 +1 @@ +15 diff --git a/vacations/output/36 b/vacations/output/36 new file mode 100644 index 0000000..8351c19 --- /dev/null +++ b/vacations/output/36 @@ -0,0 +1 @@ +14 diff --git a/vacations/output/37 b/vacations/output/37 new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/vacations/output/37 @@ -0,0 +1 @@ +1 diff --git a/vacations/output/38 b/vacations/output/38 new file mode 100644 index 0000000..4099407 --- /dev/null +++ b/vacations/output/38 @@ -0,0 +1 @@ +23 diff --git a/vacations/output/39 b/vacations/output/39 new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/vacations/output/39 @@ -0,0 +1 @@ +4 diff --git a/vacations/output/4 b/vacations/output/4 new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vacations/output/4 @@ -0,0 +1 @@ +5 diff --git a/vacations/output/40 b/vacations/output/40 new file mode 100644 index 0000000..a787364 --- /dev/null +++ b/vacations/output/40 @@ -0,0 +1 @@ +34 diff --git a/vacations/output/41 b/vacations/output/41 new file mode 100644 index 0000000..f64f5d8 --- /dev/null +++ b/vacations/output/41 @@ -0,0 +1 @@ +27 diff --git a/vacations/output/42 b/vacations/output/42 new file mode 100644 index 0000000..f04c001 --- /dev/null +++ b/vacations/output/42 @@ -0,0 +1 @@ +29 diff --git a/vacations/output/43 b/vacations/output/43 new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/vacations/output/43 @@ -0,0 +1 @@ +18 diff --git a/vacations/output/44 b/vacations/output/44 new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/vacations/output/44 @@ -0,0 +1 @@ +4 diff --git a/vacations/output/45 b/vacations/output/45 new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/vacations/output/45 @@ -0,0 +1 @@ +9 diff --git a/vacations/output/46 b/vacations/output/46 new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/vacations/output/46 @@ -0,0 +1 @@ +8 diff --git a/vacations/output/47 b/vacations/output/47 new file mode 100644 index 0000000..7273c0f --- /dev/null +++ b/vacations/output/47 @@ -0,0 +1 @@ +25 diff --git a/vacations/output/48 b/vacations/output/48 new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/vacations/output/48 @@ -0,0 +1 @@ +18 diff --git a/vacations/output/49 b/vacations/output/49 new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/vacations/output/49 @@ -0,0 +1 @@ +3 diff --git a/vacations/output/5 b/vacations/output/5 new file mode 100644 index 0000000..573541a --- /dev/null +++ b/vacations/output/5 @@ -0,0 +1 @@ +0 diff --git a/vacations/output/50 b/vacations/output/50 new file mode 100644 index 0000000..98d9bcb --- /dev/null +++ b/vacations/output/50 @@ -0,0 +1 @@ +17 diff --git a/vacations/output/51 b/vacations/output/51 new file mode 100644 index 0000000..4099407 --- /dev/null +++ b/vacations/output/51 @@ -0,0 +1 @@ +23 diff --git a/vacations/output/52 b/vacations/output/52 new file mode 100644 index 0000000..bb95160 --- /dev/null +++ b/vacations/output/52 @@ -0,0 +1 @@ +33 diff --git a/vacations/output/53 b/vacations/output/53 new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/vacations/output/53 @@ -0,0 +1 @@ +9 diff --git a/vacations/output/54 b/vacations/output/54 new file mode 100644 index 0000000..8351c19 --- /dev/null +++ b/vacations/output/54 @@ -0,0 +1 @@ +14 diff --git a/vacations/output/55 b/vacations/output/55 new file mode 100644 index 0000000..6f4247a --- /dev/null +++ b/vacations/output/55 @@ -0,0 +1 @@ +26 diff --git a/vacations/output/56 b/vacations/output/56 new file mode 100644 index 0000000..29d6383 --- /dev/null +++ b/vacations/output/56 @@ -0,0 +1 @@ +100 diff --git a/vacations/output/57 b/vacations/output/57 new file mode 100644 index 0000000..573541a --- /dev/null +++ b/vacations/output/57 @@ -0,0 +1 @@ +0 diff --git a/vacations/output/58 b/vacations/output/58 new file mode 100644 index 0000000..87523dd --- /dev/null +++ b/vacations/output/58 @@ -0,0 +1 @@ +41 diff --git a/vacations/output/59 b/vacations/output/59 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/vacations/output/59 @@ -0,0 +1 @@ +2 diff --git a/vacations/output/6 b/vacations/output/6 new file mode 100644 index 0000000..573541a --- /dev/null +++ b/vacations/output/6 @@ -0,0 +1 @@ +0 diff --git a/vacations/output/60 b/vacations/output/60 new file mode 100644 index 0000000..6f4247a --- /dev/null +++ b/vacations/output/60 @@ -0,0 +1 @@ +26 diff --git a/vacations/output/61 b/vacations/output/61 new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vacations/output/61 @@ -0,0 +1 @@ +5 diff --git a/vacations/output/62 b/vacations/output/62 new file mode 100644 index 0000000..f04c001 --- /dev/null +++ b/vacations/output/62 @@ -0,0 +1 @@ +29 diff --git a/vacations/output/63 b/vacations/output/63 new file mode 100644 index 0000000..98d9bcb --- /dev/null +++ b/vacations/output/63 @@ -0,0 +1 @@ +17 diff --git a/vacations/output/64 b/vacations/output/64 new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/vacations/output/64 @@ -0,0 +1 @@ +22 diff --git a/vacations/output/65 b/vacations/output/65 new file mode 100644 index 0000000..7273c0f --- /dev/null +++ b/vacations/output/65 @@ -0,0 +1 @@ +25 diff --git a/vacations/output/66 b/vacations/output/66 new file mode 100644 index 0000000..f64f5d8 --- /dev/null +++ b/vacations/output/66 @@ -0,0 +1 @@ +27 diff --git a/vacations/output/67 b/vacations/output/67 new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vacations/output/67 @@ -0,0 +1 @@ +5 diff --git a/vacations/output/68 b/vacations/output/68 new file mode 100644 index 0000000..60d3b2f --- /dev/null +++ b/vacations/output/68 @@ -0,0 +1 @@ +15 diff --git a/vacations/output/69 b/vacations/output/69 new file mode 100644 index 0000000..f5c8955 --- /dev/null +++ b/vacations/output/69 @@ -0,0 +1 @@ +32 diff --git a/vacations/output/7 b/vacations/output/7 new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/vacations/output/7 @@ -0,0 +1 @@ +8 diff --git a/vacations/output/70 b/vacations/output/70 new file mode 100644 index 0000000..a787364 --- /dev/null +++ b/vacations/output/70 @@ -0,0 +1 @@ +34 diff --git a/vacations/output/71 b/vacations/output/71 new file mode 100644 index 0000000..7273c0f --- /dev/null +++ b/vacations/output/71 @@ -0,0 +1 @@ +25 diff --git a/vacations/output/72 b/vacations/output/72 new file mode 100644 index 0000000..573541a --- /dev/null +++ b/vacations/output/72 @@ -0,0 +1 @@ +0 diff --git a/vacations/output/73 b/vacations/output/73 new file mode 100644 index 0000000..81b5c5d --- /dev/null +++ b/vacations/output/73 @@ -0,0 +1 @@ +37 diff --git a/vacations/output/74 b/vacations/output/74 new file mode 100644 index 0000000..d6b2404 --- /dev/null +++ b/vacations/output/74 @@ -0,0 +1 @@ +19 diff --git a/vacations/output/75 b/vacations/output/75 new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vacations/output/75 @@ -0,0 +1 @@ +5 diff --git a/vacations/output/76 b/vacations/output/76 new file mode 100644 index 0000000..e522732 --- /dev/null +++ b/vacations/output/76 @@ -0,0 +1 @@ +38 diff --git a/vacations/output/77 b/vacations/output/77 new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/vacations/output/77 @@ -0,0 +1 @@ +9 diff --git a/vacations/output/78 b/vacations/output/78 new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/vacations/output/78 @@ -0,0 +1 @@ +18 diff --git a/vacations/output/79 b/vacations/output/79 new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/vacations/output/79 @@ -0,0 +1 @@ +10 diff --git a/vacations/output/8 b/vacations/output/8 new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vacations/output/8 @@ -0,0 +1 @@ +5 diff --git a/vacations/output/80 b/vacations/output/80 new file mode 100644 index 0000000..ea90ee3 --- /dev/null +++ b/vacations/output/80 @@ -0,0 +1 @@ +45 diff --git a/vacations/output/81 b/vacations/output/81 new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/vacations/output/81 @@ -0,0 +1 @@ +18 diff --git a/vacations/output/82 b/vacations/output/82 new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/vacations/output/82 @@ -0,0 +1 @@ +8 diff --git a/vacations/output/83 b/vacations/output/83 new file mode 100644 index 0000000..60d3b2f --- /dev/null +++ b/vacations/output/83 @@ -0,0 +1 @@ +15 diff --git a/vacations/output/84 b/vacations/output/84 new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/vacations/output/84 @@ -0,0 +1 @@ +11 diff --git a/vacations/output/85 b/vacations/output/85 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/vacations/output/85 @@ -0,0 +1 @@ +2 diff --git a/vacations/output/86 b/vacations/output/86 new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/vacations/output/86 @@ -0,0 +1 @@ +10 diff --git a/vacations/output/87 b/vacations/output/87 new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/vacations/output/87 @@ -0,0 +1 @@ +7 diff --git a/vacations/output/88 b/vacations/output/88 new file mode 100644 index 0000000..e522732 --- /dev/null +++ b/vacations/output/88 @@ -0,0 +1 @@ +38 diff --git a/vacations/output/89 b/vacations/output/89 new file mode 100644 index 0000000..7273c0f --- /dev/null +++ b/vacations/output/89 @@ -0,0 +1 @@ +25 diff --git a/vacations/output/9 b/vacations/output/9 new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/vacations/output/9 @@ -0,0 +1 @@ +6 diff --git a/vacations/output/90 b/vacations/output/90 new file mode 100644 index 0000000..60d3b2f --- /dev/null +++ b/vacations/output/90 @@ -0,0 +1 @@ +15 diff --git a/vacations/output/91 b/vacations/output/91 new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/vacations/output/91 @@ -0,0 +1 @@ +7 diff --git a/vacations/output/92 b/vacations/output/92 new file mode 100644 index 0000000..d6b2404 --- /dev/null +++ b/vacations/output/92 @@ -0,0 +1 @@ +19 diff --git a/vacations/output/93 b/vacations/output/93 new file mode 100644 index 0000000..b1bd38b --- /dev/null +++ b/vacations/output/93 @@ -0,0 +1 @@ +13 diff --git a/vacations/output/94 b/vacations/output/94 new file mode 100644 index 0000000..64bb6b7 --- /dev/null +++ b/vacations/output/94 @@ -0,0 +1 @@ +30 diff --git a/vacations/output/95 b/vacations/output/95 new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/vacations/output/95 @@ -0,0 +1 @@ +12 diff --git a/vacations/output/96 b/vacations/output/96 new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vacations/output/96 @@ -0,0 +1 @@ +5 diff --git a/vacations/output/97 b/vacations/output/97 new file mode 100644 index 0000000..b6a7d89 --- /dev/null +++ b/vacations/output/97 @@ -0,0 +1 @@ +16 diff --git a/vacations/output/98 b/vacations/output/98 new file mode 100644 index 0000000..8351c19 --- /dev/null +++ b/vacations/output/98 @@ -0,0 +1 @@ +14 diff --git a/vacations/output/99 b/vacations/output/99 new file mode 100644 index 0000000..7facc89 --- /dev/null +++ b/vacations/output/99 @@ -0,0 +1 @@ +36 diff --git a/vacations/problem.json b/vacations/problem.json new file mode 100644 index 0000000..3e5d2fb --- /dev/null +++ b/vacations/problem.json @@ -0,0 +1,64 @@ +{ + "version": "1.0", + "problem": { + "title": "Férias", + "event": "", + "time_limit": 1.0, + "memory_limit_mb": 256, + "input_file": "stdin", + "output_file": "stdout", + "interactive": false, + "grader": false, + "subject": { + "en_us": [ + "dynamic-programming" + ], + "pt_br": [ + "programação-dinâmica" + ], + "es": [ + "" + ] + } + }, + "author": { + "name": "Codeforces 363 (Div. 1)", + "affiliation": "", + "country": "", + "email": "" + }, + "build": { + "run_generator": true, + "run_validator": true, + "produce_outputs": true, + "run_checker": true, + "run_all_solutions": true, + "run_specific_solution": "", + "generate_io_only": false, + "generate_pdf_only": false, + "cpu_count": 1, + "build_pdf": true, + "pdf_format": "ds", + "io_samples": 3 + }, + "solutions": { + "main-ac": "ac.cpp", + "alternative-ac": [], + "wrong-answer": [], + "time-limit": ["TLE.cpp"], + "time-limit-or-ac": [], + "time-limit-or-memory-limit": [], + "memory-limit": [], + "presentation-error": [], + "runtime-error": [] + }, + "polygon_config": { + "id": "" + }, + "boca_config": { + "time_limit": 1, + "number_of_repetitions": 1, + "maximum_memory_mb": 512, + "maximum_output_size_kb": 24096 + } +} \ No newline at end of file diff --git a/vacations/src/TLE.cpp b/vacations/src/TLE.cpp new file mode 100644 index 0000000..d10d902 --- /dev/null +++ b/vacations/src/TLE.cpp @@ -0,0 +1,45 @@ +#include + +using namespace std; + +/* + vacations(d, last) answers to distance d ending with character last +*/ +int vacations(int d, char last, vector &days) { + if (d == 0) return 0; + + int cur = days[days.size() - d]; + int best = INT_MAX; + if (last == 'R') { + if (cur == 3 || cur == 4) { + best = vacations(d - 1, 'G', days); + } + if (cur == 2 || cur == 4) { + best = min(best, vacations(d - 1, 'C', days)); + } + best = min(best, vacations(d - 1, 'R', days) + 1); + } else if (last == 'C') { + if (cur == 3 || cur == 4) { + best = vacations(d - 1, 'G', days); + } + best = min(best, vacations(d - 1, 'R', days) + 1); + } else if (last == 'G') { + if (cur == 2 || cur == 4) { + best = min(best, vacations(d - 1, 'C', days)); + } + best = min(best, vacations(d - 1, 'R', days) + 1); + } + + return best; +} + +int main(){ + int n; cin >> n; + vector A(n); + for (int i = 0; i < n; i++) { + cin >> A[i]; + A[i]++; + } + cout << min({vacations(n, 'R', A) + 1, vacations(n, 'C', A), vacations(n, 'G', A)}) << endl; + return 0; +} \ No newline at end of file diff --git a/vacations/src/ac.cpp b/vacations/src/ac.cpp new file mode 100644 index 0000000..5960db7 --- /dev/null +++ b/vacations/src/ac.cpp @@ -0,0 +1,42 @@ +#include + +using namespace std; + +/* + let dp[i][j] be the minimum number of R's appering in a sequence + of length i with the last character beeing j + + 0 -> R + 1 -> C + 2 -> G +*/ +int main(){ + int n; cin >> n; + vector A(n + 1); + for (int i = 1; i <= n; i++) { + cin >> A[i]; + } + + vector> dp(n + 1, vector(3, 0)); + for (int i = 1; i <= n; i++) { + int cur = A[i]; + dp[i][0] = min({dp[i - 1][0], dp[i - 1][1], dp[i - 1][2]}) + 1; + if (cur == 0) { + dp[i][1] = INT_MAX; + dp[i][2] = INT_MAX; + } else if (cur == 1) { + dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]); + dp[i][2] = INT_MAX; + } else if (cur == 2) { + dp[i][1] = INT_MAX; + dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]); + } else { + dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]); + dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]); + } + } + + cout << min({dp[n][0], dp[n][1], dp[n][2]}) << endl; + + return 0; +} \ No newline at end of file diff --git a/vacations/src/checker.cpp b/vacations/src/checker.cpp new file mode 100644 index 0000000..d1d2302 --- /dev/null +++ b/vacations/src/checker.cpp @@ -0,0 +1,19 @@ +#include "testlib.h" +#include + + +using namespace std; + + +int main(int argc, char* argv[]) { + setName("compare two signed int%d's", 8 * int(sizeof(int))); + registerTestlibCmd(argc, argv); + + int ja = ans.readInt(); + int pa = ouf.readInt(); + + if (ja != pa) + quitf(_wa, "expected %d, found %d", ja, pa); + + quitf(_ok, "answer is %d", ja); +} \ No newline at end of file diff --git a/vacations/src/generator.cpp b/vacations/src/generator.cpp new file mode 100644 index 0000000..9cd8bff --- /dev/null +++ b/vacations/src/generator.cpp @@ -0,0 +1,106 @@ +#include "testlib.h" +#include + +using namespace std; + +const int MIN_N = 1; +const int MAX_N = 100; +const int MIN_NI = 0; +const int MAX_NI = 3; + +const int rnd_test_n = 50; + +template void append(vector &dest, const vector &orig) { + dest.insert(dest.end(), orig.begin(), orig.end()); +} + +string output_tc(const vector &nums) { + ostringstream oss; + oss << nums.size() << endl; + for (int i = 0; i < nums.size(); i++) { + if (i != 0) oss << " "; + oss << nums[i]; + } + oss << endl; + return oss.str(); +} + +vector generate_sample_tests() { + vector tests; + tests.push_back(output_tc({1, 3, 2, 0})); + tests.push_back(output_tc({1, 3, 3, 2, 1, 2, 3})); + tests.push_back(output_tc({2, 2})); + return tests; +} + +vector generate_manual_tests() { + vector tests; + tests.push_back(output_tc({0, 0, 0, 0, 0})); + tests.push_back(output_tc({3, 3, 3, 3, 3})); + return tests; +} + +string rnd_test(int i){ + int min_n = MIN_N; + int max_n = MAX_N; + + if(i nums(n); + for (int i = 0; i < n; i++) { + nums[i] = rnd.next(MIN_NI, MAX_NI); + } + return(output_tc(nums)); +} + +vector generate_random_tests() { + vector tests; + for (int i = 0; i < rnd_test_n; i++){ + tests.push_back(rnd_test(i)); + } + return tests; +} + +string extreme_test_1(){ + vector nums(MAX_N); + for (int i = 0; i < MAX_N; i++) { + nums[i] = MIN_NI; + } + return(output_tc(nums)); +} + +string extreme_test_2(){ + vector nums(MAX_N); + for (int i = 0; i < MAX_N; i++) { + nums[i] = MAX_NI; + } + return(output_tc(nums)); +} + +vector generate_extreme_tests(){ + vector tests; + tests.push_back(extreme_test_1()); + tests.push_back(extreme_test_2()); + return tests; +} + +int main(int argc, char *argv[]) { + registerGen(argc, argv, 1); + vector tests; + size_t test = 0; + append(tests, generate_sample_tests()); + append(tests, generate_manual_tests()); + append(tests, generate_random_tests()); + append(tests, generate_extreme_tests()); + for (const auto &t : tests) { + startTest(++test); + cout << t; + } + return 0; +} \ No newline at end of file diff --git a/vacations/src/script.sh b/vacations/src/script.sh new file mode 100644 index 0000000..a8a6bda --- /dev/null +++ b/vacations/src/script.sh @@ -0,0 +1 @@ +generator \ No newline at end of file diff --git a/vacations/src/testlib.h b/vacations/src/testlib.h new file mode 100644 index 0000000..fac02ad --- /dev/null +++ b/vacations/src/testlib.h @@ -0,0 +1,5963 @@ +/* + * It is strictly recommended to include "testlib.h" before any other include + * in your code. In this case testlib overrides compiler specific "random()". + * + * If you can't compile your code and compiler outputs something about + * ambiguous call of "random_shuffle", "rand" or "srand" it means that + * you shouldn't use them. Use "shuffle", and "rnd.next()" instead of them + * because these calls produce stable result for any C++ compiler. Read + * sample generator sources for clarification. + * + * Please read the documentation for class "random_t" and use "rnd" instance in + * generators. Probably, these sample calls will be usefull for you: + * rnd.next(); rnd.next(100); rnd.next(1, 2); + * rnd.next(3.14); rnd.next("[a-z]{1,100}"). + * + * Also read about wnext() to generate off-center random distribution. + * + * See https://github.com/MikeMirzayanov/testlib/ to get latest version or bug tracker. + */ + +#ifndef _TESTLIB_H_ +#define _TESTLIB_H_ + +/* + * Copyright (c) 2005-2022 + */ + +#define VERSION "0.9.40-SNAPSHOT" + +/* + * Mike Mirzayanov + * + * This material is provided "as is", with absolutely no warranty expressed + * or implied. Any use is at your own risk. + * + * Permission to use or copy this software for any purpose is hereby granted + * without fee, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + * + */ + +/* NOTE: This file contains testlib library for C++. + * + * Check, using testlib running format: + * check.exe [ [-appes]], + * If result file is specified it will contain results. + * + * Validator, using testlib running format: + * validator.exe < input.txt, + * It will return non-zero exit code and writes message to standard output. + * + * Generator, using testlib running format: + * gen.exe [parameter-1] [parameter-2] [... paramerter-n] + * You can write generated test(s) into standard output or into the file(s). + * + * Interactor, using testlib running format: + * interactor.exe [ [ [-appes]]], + * Reads test from inf (mapped to args[1]), writes result to tout (mapped to argv[2], + * can be judged by checker later), reads program output from ouf (mapped to stdin), + * writes output to program via stdout (use cout, printf, etc). + */ + +const char *latestFeatures[] = { + "Supported '--testMarkupFileName fn' and '--testCase tc/--testCaseFileName fn' for validators", + "Added opt defaults via opt(key/index, default_val); check unused opts when using has_opt or default opt (turn off this check with suppressEnsureNoUnusedOpt()).", + "For checker added --group and --testset command line params (like for validator), use checker.group() or checker.testset() to get values", + "Added quitpi(points_info, message) function to return with _points exit code 7 and given points_info", + "rnd.partition(size, sum[, min_part=1]) returns random (unsorted) partition which is a representation of the given `sum` as a sum of `size` positive integers (or >=min_part if specified)", + "rnd.distinct(size, n) and rnd.distinct(size, from, to)", + "opt(\"some_missing_key\") returns false now", + "has_opt(key)", + "Abort validator on validator.testset()/validator.group() if registered without using command line", + "Print integer range violations in a human readable way like `violates the range [1, 10^9]`", + "Opts supported: use them like n = opt(\"n\"), in a command line you can use an exponential notation", + "Reformatted", + "Use setTestCase(i) or unsetTestCase() to support test cases (you can use it in any type of program: generator, interactor, validator or checker)", + "Fixed issue #87: readStrictDouble accepts \"-0.00\"", + "Fixed issue #83: added InStream::quitif(condition, ...)", + "Fixed issue #79: fixed missed guard against repeated header include", + "Fixed issue #80: fixed UB in case of huge quitf message", + "Fixed issue #84: added readXs(size, indexBase = 1)", + "Fixed stringstream repeated usage issue", + "Fixed compilation in g++ (for std=c++03)", + "Batch of println functions (support collections, iterator ranges)", + "Introduced rnd.perm(size, first = 0) to generate a `first`-indexed permutation", + "Allow any whitespace in readInts-like functions for non-validators", + "Ignore 4+ command line arguments ifdef EJUDGE", + "Speed up of vtos", + "Show line number in validators in case of incorrect format", + "Truncate huge checker/validator/interactor message", + "Fixed issue with readTokenTo of very long tokens, now aborts with _pe/_fail depending of a stream type", + "Introduced InStream::ensure/ensuref checking a condition, returns wa/fail depending of a stream type", + "Fixed compilation in VS 2015+", + "Introduced space-separated read functions: readWords/readTokens, multilines read functions: readStrings/readLines", + "Introduced space-separated read functions: readInts/readIntegers/readLongs/readUnsignedLongs/readDoubles/readReals/readStrictDoubles/readStrictReals", + "Introduced split/tokenize functions to separate string by given char", + "Introduced InStream::readUnsignedLong and InStream::readLong with unsigned long long paramerters", + "Supported --testOverviewLogFileName for validator: bounds hits + features", + "Fixed UB (sequence points) in random_t", + "POINTS_EXIT_CODE returned back to 7 (instead of 0)", + "Removed disable buffers for interactive problems, because it works unexpectedly in wine", + "InStream over string: constructor of InStream from base InStream to inherit policies and std::string", + "Added expectedButFound quit function, examples: expectedButFound(_wa, 10, 20), expectedButFound(_fail, ja, pa, \"[n=%d,m=%d]\", n, m)", + "Fixed incorrect interval parsing in patterns", + "Use registerGen(argc, argv, 1) to develop new generator, use registerGen(argc, argv, 0) to compile old generators (originally created for testlib under 0.8.7)", + "Introduced disableFinalizeGuard() to switch off finalization checkings", + "Use join() functions to format a range of items as a single string (separated by spaces or other separators)", + "Use -DENABLE_UNEXPECTED_EOF to enable special exit code (by default, 8) in case of unexpected eof. It is good idea to use it in interactors", + "Use -DUSE_RND_AS_BEFORE_087 to compile in compatibility mode with random behavior of versions before 0.8.7", + "Fixed bug with nan in stringToDouble", + "Fixed issue around overloads for size_t on x64", + "Added attribute 'points' to the XML output in case of result=_points", + "Exit codes can be customized via macros, e.g. -DPE_EXIT_CODE=14", + "Introduced InStream function readWordTo/readTokenTo/readStringTo/readLineTo for faster reading", + "Introduced global functions: format(), englishEnding(), upperCase(), lowerCase(), compress()", + "Manual buffer in InStreams, some IO speed improvements", + "Introduced quitif(bool, const char* pattern, ...) which delegates to quitf() in case of first argument is true", + "Introduced guard against missed quitf() in checker or readEof() in validators", + "Supported readStrictReal/readStrictDouble - to use in validators to check strictly float numbers", + "Supported registerInteraction(argc, argv)", + "Print checker message to the stderr instead of stdout", + "Supported TResult _points to output calculated score, use quitp(...) functions", + "Fixed to be compilable on Mac", + "PC_BASE_EXIT_CODE=50 in case of defined TESTSYS", + "Fixed issues 19-21, added __attribute__ format printf", + "Some bug fixes", + "ouf.readInt(1, 100) and similar calls return WA", + "Modified random_t to avoid integer overflow", + "Truncated checker output [patch by Stepan Gatilov]", + "Renamed class random -> class random_t", + "Supported name parameter for read-and-validation methods, like readInt(1, 2, \"n\")", + "Fixed bug in readDouble()", + "Improved ensuref(), fixed nextLine to work in case of EOF, added startTest()", + "Supported \"partially correct\", example: quitf(_pc(13), \"result=%d\", result)", + "Added shuffle(begin, end), use it instead of random_shuffle(begin, end)", + "Added readLine(const string& ptrn), fixed the logic of readLine() in the validation mode", + "Package extended with samples of generators and validators", + "Written the documentation for classes and public methods in testlib.h", + "Implemented random routine to support generators, use registerGen() to switch it on", + "Implemented strict mode to validate tests, use registerValidation() to switch it on", + "Now ncmp.cpp and wcmp.cpp are return WA if answer is suffix or prefix of the output", + "Added InStream::readLong() and removed InStream::readLongint()", + "Now no footer added to each report by default (use directive FOOTER to switch on)", + "Now every checker has a name, use setName(const char* format, ...) to set it", + "Now it is compatible with TTS (by Kittens Computing)", + "Added \'ensure(condition, message = \"\")\' feature, it works like assert()", + "Fixed compatibility with MS C++ 7.1", + "Added footer with exit code information", + "Added compatibility with EJUDGE (compile with EJUDGE directive)", + "Added compatibility with Contester (compile with CONTESTER directive)" +}; + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_NO_VA_START_VALIDATION +#endif + +/* Overrides random() for Borland C++. */ +#define random __random_deprecated +#include +#include +#include +#include +#undef random + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TESTLIB_THROW_EXIT_EXCEPTION_INSTEAD_OF_EXIT +# include +#endif + +#if (_WIN32 || __WIN32__ || __WIN32 || _WIN64 || __WIN64__ || __WIN64 || WINNT || __WINNT || __WINNT__ || __CYGWIN__) +# if !defined(_MSC_VER) || _MSC_VER > 1400 +# define NOMINMAX 1 +# include +# else +# define WORD unsigned short +# include +# endif +# include +# define ON_WINDOWS +# if defined(_MSC_VER) && _MSC_VER > 1400 +# pragma warning( disable : 4127 ) +# pragma warning( disable : 4146 ) +# pragma warning( disable : 4458 ) +# endif +#else +# define WORD unsigned short +# include +#endif + +#if defined(FOR_WINDOWS) && defined(FOR_LINUX) +#error Only one target system is allowed +#endif + +#ifndef LLONG_MIN +#define LLONG_MIN (-9223372036854775807LL - 1) +#endif + +#ifndef ULLONG_MAX +#define ULLONG_MAX (18446744073709551615) +#endif + +#define LF ((char)10) +#define CR ((char)13) +#define TAB ((char)9) +#define SPACE ((char)' ') +#define EOFC (255) + +#ifndef OK_EXIT_CODE +# ifdef CONTESTER +# define OK_EXIT_CODE 0xAC +# elif defined BOCA_SUPPORT +# define OK_EXIT_CODE 4 +# else +# define OK_EXIT_CODE 0 +# endif +#endif + +#ifndef WA_EXIT_CODE +# ifdef EJUDGE +# define WA_EXIT_CODE 5 +# elif defined(CONTESTER) +# define WA_EXIT_CODE 0xAB +# elif defined BOCA_SUPPORT +# define WA_EXIT_CODE 6 +# else +# define WA_EXIT_CODE 1 +# endif +#endif + +#ifndef PE_EXIT_CODE +# ifdef EJUDGE +# define PE_EXIT_CODE 4 +# elif defined(CONTESTER) +# define PE_EXIT_CODE 0xAA +# elif defined BOCA_SUPPORT +# define PE_EXIT_CODE 6 +# else +# define PE_EXIT_CODE 2 +# endif +#endif + +#ifndef FAIL_EXIT_CODE +# ifdef EJUDGE +# define FAIL_EXIT_CODE 6 +# elif defined(CONTESTER) +# define FAIL_EXIT_CODE 0xA3 +# elif defined BOCA_SUPPORT +# define FAIL_EXIT_CODE 7 +# else +# define FAIL_EXIT_CODE 3 +# endif +#endif + +#ifndef DIRT_EXIT_CODE +# ifdef EJUDGE +# define DIRT_EXIT_CODE 6 +# else +# define DIRT_EXIT_CODE 4 +# endif +#endif + +#ifndef POINTS_EXIT_CODE +# ifndef BOCA_SUPPORT +# define POINTS_EXIT_CODE 7 +# else +# define POINTS_EXIT_CODE 5 +# endif +#endif + +#ifndef UNEXPECTED_EOF_EXIT_CODE +# define UNEXPECTED_EOF_EXIT_CODE 8 +#endif + +#ifndef PC_BASE_EXIT_CODE +# ifdef TESTSYS +# define PC_BASE_EXIT_CODE 50 +# else +# define PC_BASE_EXIT_CODE 0 +# endif +#endif + +#ifdef __GNUC__ +# define __TESTLIB_STATIC_ASSERT(condition) typedef void* __testlib_static_assert_type[(condition) ? 1 : -1] __attribute__((unused)) +#else +# define __TESTLIB_STATIC_ASSERT(condition) typedef void* __testlib_static_assert_type[(condition) ? 1 : -1] +#endif + +#ifdef ON_WINDOWS +#define I64 "%I64d" +#define U64 "%I64u" +#else +#define I64 "%lld" +#define U64 "%llu" +#endif + +#ifdef _MSC_VER +# define NORETURN __declspec(noreturn) +#elif defined __GNUC__ +# define NORETURN __attribute__ ((noreturn)) +#else +# define NORETURN +#endif + +static char __testlib_format_buffer[16777216]; +static int __testlib_format_buffer_usage_count = 0; + +#define FMT_TO_RESULT(fmt, cstr, result) std::string result; \ + if (__testlib_format_buffer_usage_count != 0) \ + __testlib_fail("FMT_TO_RESULT::__testlib_format_buffer_usage_count != 0"); \ + __testlib_format_buffer_usage_count++; \ + va_list ap; \ + va_start(ap, fmt); \ + vsnprintf(__testlib_format_buffer, sizeof(__testlib_format_buffer), cstr, ap); \ + va_end(ap); \ + __testlib_format_buffer[sizeof(__testlib_format_buffer) - 1] = 0; \ + result = std::string(__testlib_format_buffer); \ + __testlib_format_buffer_usage_count--; \ + +const long long __TESTLIB_LONGLONG_MAX = 9223372036854775807LL; +const int __TESTLIB_MAX_TEST_CASE = 1073741823; + +int __testlib_exitCode; + +bool __testlib_hasTestCase; +int __testlib_testCase = -1; + +void setTestCase(int testCase); + +void unsetTestCase() { + __testlib_hasTestCase = false; + __testlib_testCase = -1; +} + +NORETURN static void __testlib_fail(const std::string &message); + +template +static inline T __testlib_abs(const T &x) { + return x > 0 ? x : -x; +} + +template +static inline T __testlib_min(const T &a, const T &b) { + return a < b ? a : b; +} + +template +static inline T __testlib_max(const T &a, const T &b) { + return a > b ? a : b; +} + +template +static inline T __testlib_crop(T value, T a, T b) { + return __testlib_min(__testlib_max(value, a), --b); +} + +static inline double __testlib_crop(double value, double a, double b) { + value = __testlib_min(__testlib_max(value, a), b); + if (value >= b) + value = std::nexttoward(b, a); + return value; +} + +static bool __testlib_prelimIsNaN(double r) { + volatile double ra = r; +#ifndef __BORLANDC__ + return ((ra != ra) == true) && ((ra == ra) == false) && ((1.0 > ra) == false) && ((1.0 < ra) == false); +#else + return std::_isnan(ra); +#endif +} + +static std::string removeDoubleTrailingZeroes(std::string value) { + while (!value.empty() && value[value.length() - 1] == '0' && value.find('.') != std::string::npos) + value = value.substr(0, value.length() - 1); + if (!value.empty() && value[value.length() - 1] == '.') + return value + '0'; + else + return value; +} + +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +std::string format(const char *fmt, ...) { + FMT_TO_RESULT(fmt, fmt, result); + return result; +} + +std::string format(const std::string fmt, ...) { + FMT_TO_RESULT(fmt, fmt.c_str(), result); + return result; +} + +static std::string __testlib_part(const std::string &s); + +static bool __testlib_isNaN(double r) { + __TESTLIB_STATIC_ASSERT(sizeof(double) == sizeof(long long)); + volatile double ra = r; + long long llr1, llr2; + std::memcpy((void *) &llr1, (void *) &ra, sizeof(double)); + ra = -ra; + std::memcpy((void *) &llr2, (void *) &ra, sizeof(double)); + long long llnan = 0xFFF8000000000000LL; + return __testlib_prelimIsNaN(r) || llnan == llr1 || llnan == llr2; +} + +static double __testlib_nan() { + __TESTLIB_STATIC_ASSERT(sizeof(double) == sizeof(long long)); +#ifndef NAN + long long llnan = 0xFFF8000000000000LL; + double nan; + std::memcpy(&nan, &llnan, sizeof(double)); + return nan; +#else + return NAN; +#endif +} + +static bool __testlib_isInfinite(double r) { + volatile double ra = r; + return (ra > 1E300 || ra < -1E300); +} + +#ifdef __GNUC__ +__attribute__((const)) +#endif +inline bool doubleCompare(double expected, double result, double MAX_DOUBLE_ERROR) { + MAX_DOUBLE_ERROR += 1E-15; + if (__testlib_isNaN(expected)) { + return __testlib_isNaN(result); + } else if (__testlib_isInfinite(expected)) { + if (expected > 0) { + return result > 0 && __testlib_isInfinite(result); + } else { + return result < 0 && __testlib_isInfinite(result); + } + } else if (__testlib_isNaN(result) || __testlib_isInfinite(result)) { + return false; + } else if (__testlib_abs(result - expected) <= MAX_DOUBLE_ERROR) { + return true; + } else { + double minv = __testlib_min(expected * (1.0 - MAX_DOUBLE_ERROR), + expected * (1.0 + MAX_DOUBLE_ERROR)); + double maxv = __testlib_max(expected * (1.0 - MAX_DOUBLE_ERROR), + expected * (1.0 + MAX_DOUBLE_ERROR)); + return result >= minv && result <= maxv; + } +} + +#ifdef __GNUC__ +__attribute__((const)) +#endif +inline double doubleDelta(double expected, double result) { + double absolute = __testlib_abs(result - expected); + + if (__testlib_abs(expected) > 1E-9) { + double relative = __testlib_abs(absolute / expected); + return __testlib_min(absolute, relative); + } else + return absolute; +} + +/** It does nothing on non-windows and files differ from stdin/stdout/stderr. */ +static void __testlib_set_binary(std::FILE *file) { + if (NULL != file) { +#ifdef ON_WINDOWS +# ifdef _O_BINARY + if (stdin == file) +# ifdef STDIN_FILENO + return void(_setmode(STDIN_FILENO, _O_BINARY)); +# else + return void(_setmode(_fileno(stdin), _O_BINARY)); +# endif + if (stdout == file) +# ifdef STDOUT_FILENO + return void(_setmode(STDOUT_FILENO, _O_BINARY)); +# else + return void(_setmode(_fileno(stdout), _O_BINARY)); +# endif + if (stderr == file) +# ifdef STDERR_FILENO + return void(_setmode(STDERR_FILENO, _O_BINARY)); +# else + return void(_setmode(_fileno(stderr), _O_BINARY)); +# endif +# elif O_BINARY + if (stdin == file) +# ifdef STDIN_FILENO + return void(setmode(STDIN_FILENO, O_BINARY)); +# else + return void(setmode(fileno(stdin), O_BINARY)); +# endif + if (stdout == file) +# ifdef STDOUT_FILENO + return void(setmode(STDOUT_FILENO, O_BINARY)); +# else + return void(setmode(fileno(stdout), O_BINARY)); +# endif + if (stderr == file) +# ifdef STDERR_FILENO + return void(setmode(STDERR_FILENO, O_BINARY)); +# else + return void(setmode(fileno(stderr), O_BINARY)); +# endif +# endif +#endif + } +} + +#if __cplusplus > 199711L || defined(_MSC_VER) +template +static std::string vtos(const T &t, std::true_type) { + if (t == 0) + return "0"; + else { + T n(t); + bool negative = n < 0; + std::string s; + while (n != 0) { + T digit = n % 10; + if (digit < 0) + digit = -digit; + s += char('0' + digit); + n /= 10; + } + std::reverse(s.begin(), s.end()); + return negative ? "-" + s : s; + } +} + +template +static std::string vtos(const T &t, std::false_type) { + std::string s; + static std::stringstream ss; + ss.str(std::string()); + ss.clear(); + ss << t; + ss >> s; + return s; +} + +template +static std::string vtos(const T &t) { + return vtos(t, std::is_integral()); +} + +/* signed case. */ +template +static std::string toHumanReadableString(const T &n, std::false_type) { + if (n == 0) + return vtos(n); + int trailingZeroCount = 0; + T n_ = n; + while (n_ % 10 == 0) + n_ /= 10, trailingZeroCount++; + if (trailingZeroCount >= 7) { + if (n_ == 1) + return "10^" + vtos(trailingZeroCount); + else if (n_ == -1) + return "-10^" + vtos(trailingZeroCount); + else + return vtos(n_) + "*10^" + vtos(trailingZeroCount); + } else + return vtos(n); +} + +/* unsigned case. */ +template +static std::string toHumanReadableString(const T &n, std::true_type) { + if (n == 0) + return vtos(n); + int trailingZeroCount = 0; + T n_ = n; + while (n_ % 10 == 0) + n_ /= 10, trailingZeroCount++; + if (trailingZeroCount >= 7) { + if (n_ == 1) + return "10^" + vtos(trailingZeroCount); + else + return vtos(n_) + "*10^" + vtos(trailingZeroCount); + } else + return vtos(n); +} + +template +static std::string toHumanReadableString(const T &n) { + return toHumanReadableString(n, std::is_unsigned()); +} +#else +template +static std::string vtos(const T& t) +{ + std::string s; + static std::stringstream ss; + ss.str(std::string()); + ss.clear(); + ss << t; + ss >> s; + return s; +} + +template +static std::string toHumanReadableString(const T &n) { + return vtos(n); +} +#endif + +template +static std::string toString(const T &t) { + return vtos(t); +} + +#if __cplusplus > 199711L || defined(_MSC_VER) +/* opts */ +void prepareOpts(int argc, char* argv[]); +#endif + +/* + * Very simple regex-like pattern. + * It used for two purposes: validation and generation. + * + * For example, pattern("[a-z]{1,5}").next(rnd) will return + * random string from lowercase latin letters with length + * from 1 to 5. It is easier to call rnd.next("[a-z]{1,5}") + * for the same effect. + * + * Another samples: + * "mike|john" will generate (match) "mike" or "john"; + * "-?[1-9][0-9]{0,3}" will generate (match) non-zero integers from -9999 to 9999; + * "id-([ac]|b{2})" will generate (match) "id-a", "id-bb", "id-c"; + * "[^0-9]*" will match sequences (empty or non-empty) without digits, you can't + * use it for generations. + * + * You can't use pattern for generation if it contains meta-symbol '*'. Also it + * is not recommended to use it for char-sets with meta-symbol '^' like [^a-z]. + * + * For matching very simple greedy algorithm is used. For example, pattern + * "[0-9]?1" will not match "1", because of greedy nature of matching. + * Alternations (meta-symbols "|") are processed with brute-force algorithm, so + * do not use many alternations in one expression. + * + * If you want to use one expression many times it is better to compile it into + * a single pattern like "pattern p("[a-z]+")". Later you can use + * "p.matches(std::string s)" or "p.next(random_t& rd)" to check matching or generate + * new string by pattern. + * + * Simpler way to read token and check it for pattern matching is "inf.readToken("[a-z]+")". + * + * All spaces are ignored in regex, unless escaped with \. For example, ouf.readLine("NO SOLUTION") + * will expect "NOSOLUTION", the correct call should be ouf.readLine("NO\\ SOLUTION") or + * ouf.readLine(R"(NO\ SOLUTION)") if you prefer raw string literals from C++11. + */ +class random_t; + +class pattern { +public: + /* Create pattern instance by string. */ + pattern(std::string s); + + /* Generate new string by pattern and given random_t. */ + std::string next(random_t &rnd) const; + + /* Checks if given string match the pattern. */ + bool matches(const std::string &s) const; + + /* Returns source string of the pattern. */ + std::string src() const; + +private: + bool matches(const std::string &s, size_t pos) const; + + std::string s; + std::vector children; + std::vector chars; + int from; + int to; +}; + +/* + * Use random_t instances to generate random values. It is preffered + * way to use randoms instead of rand() function or self-written + * randoms. + * + * Testlib defines global variable "rnd" of random_t class. + * Use registerGen(argc, argv, 1) to setup random_t seed be command + * line (to use latest random generator version). + * + * Random generates uniformly distributed values if another strategy is + * not specified explicitly. + */ +class random_t { +private: + unsigned long long seed; + static const unsigned long long multiplier; + static const unsigned long long addend; + static const unsigned long long mask; + static const int lim; + + long long nextBits(int bits) { + if (bits <= 48) { + seed = (seed * multiplier + addend) & mask; + return (long long) (seed >> (48 - bits)); + } else { + if (bits > 63) + __testlib_fail("random_t::nextBits(int bits): n must be less than 64"); + + int lowerBitCount = (random_t::version == 0 ? 31 : 32); + + long long left = (nextBits(31) << 32); + long long right = nextBits(lowerBitCount); + + return left ^ right; + } + } + +public: + static int version; + + /* New random_t with fixed seed. */ + random_t() + : seed(3905348978240129619LL) { + } + + /* Sets seed by command line. */ + void setSeed(int argc, char *argv[]) { + random_t p; + + seed = 3905348978240129619LL; + for (int i = 1; i < argc; i++) { + std::size_t le = std::strlen(argv[i]); + for (std::size_t j = 0; j < le; j++) + seed = seed * multiplier + (unsigned int) (argv[i][j]) + addend; + seed += multiplier / addend; + } + + seed = seed & mask; + } + + /* Sets seed by given value. */ + void setSeed(long long _seed) { + _seed = (_seed ^ multiplier) & mask; + seed = _seed; + } + +#ifndef __BORLANDC__ + + /* Random string value by given pattern (see pattern documentation). */ + std::string next(const std::string &ptrn) { + pattern p(ptrn); + return p.next(*this); + } + +#else + /* Random string value by given pattern (see pattern documentation). */ + std::string next(std::string ptrn) + { + pattern p(ptrn); + return p.next(*this); + } +#endif + + /* Random value in range [0, n-1]. */ + int next(int n) { + if (n <= 0) + __testlib_fail("random_t::next(int n): n must be positive"); + + if ((n & -n) == n) // n is a power of 2 + return (int) ((n * (long long) nextBits(31)) >> 31); + + const long long limit = INT_MAX / n * n; + + long long bits; + do { + bits = nextBits(31); + } while (bits >= limit); + + return int(bits % n); + } + + /* Random value in range [0, n-1]. */ + unsigned int next(unsigned int n) { + if (n >= INT_MAX) + __testlib_fail("random_t::next(unsigned int n): n must be less INT_MAX"); + return (unsigned int) next(int(n)); + } + + /* Random value in range [0, n-1]. */ + long long next(long long n) { + if (n <= 0) + __testlib_fail("random_t::next(long long n): n must be positive"); + + const long long limit = __TESTLIB_LONGLONG_MAX / n * n; + + long long bits; + do { + bits = nextBits(63); + } while (bits >= limit); + + return bits % n; + } + + /* Random value in range [0, n-1]. */ + unsigned long long next(unsigned long long n) { + if (n >= (unsigned long long) (__TESTLIB_LONGLONG_MAX)) + __testlib_fail("random_t::next(unsigned long long n): n must be less LONGLONG_MAX"); + return (unsigned long long) next((long long) (n)); + } + + /* Random value in range [0, n-1]. */ + long next(long n) { + return (long) next((long long) (n)); + } + + /* Random value in range [0, n-1]. */ + unsigned long next(unsigned long n) { + if (n >= (unsigned long) (LONG_MAX)) + __testlib_fail("random_t::next(unsigned long n): n must be less LONG_MAX"); + return (unsigned long) next((unsigned long long) (n)); + } + + /* Returns random value in range [from,to]. */ + int next(int from, int to) { + return int(next((long long) to - from + 1) + from); + } + + /* Returns random value in range [from,to]. */ + unsigned int next(unsigned int from, unsigned int to) { + return (unsigned int) (next((long long) to - from + 1) + from); + } + + /* Returns random value in range [from,to]. */ + long long next(long long from, long long to) { + return next(to - from + 1) + from; + } + + /* Returns random value in range [from,to]. */ + unsigned long long next(unsigned long long from, unsigned long long to) { + if (from > to) + __testlib_fail("random_t::next(unsigned long long from, unsigned long long to): from can't not exceed to"); + return next(to - from + 1) + from; + } + + /* Returns random value in range [from,to]. */ + long next(long from, long to) { + return next(to - from + 1) + from; + } + + /* Returns random value in range [from,to]. */ + unsigned long next(unsigned long from, unsigned long to) { + if (from > to) + __testlib_fail("random_t::next(unsigned long from, unsigned long to): from can't not exceed to"); + return next(to - from + 1) + from; + } + + /* Random double value in range [0, 1). */ + double next() { + long long left = ((long long) (nextBits(26)) << 27); + long long right = nextBits(27); + return __testlib_crop((double) (left + right) / (double) (1LL << 53), 0.0, 1.0); + } + + /* Random double value in range [0, n). */ + double next(double n) { + if (n <= 0.0) + __testlib_fail("random_t::next(double): n should be positive"); + return __testlib_crop(n * next(), 0.0, n); + } + + /* Random double value in range [from, to). */ + double next(double from, double to) { + if (from >= to) + __testlib_fail("random_t::next(double from, double to): from should be strictly less than to"); + return next(to - from) + from; + } + + /* Returns random element from container. */ + template + typename Container::value_type any(const Container &c) { + int size = int(c.size()); + if (size <= 0) + __testlib_fail("random_t::any(const Container& c): c.size() must be positive"); + return *(c.begin() + next(size)); + } + + /* Returns random element from iterator range. */ + template + typename Iter::value_type any(const Iter &begin, const Iter &end) { + int size = int(end - begin); + if (size <= 0) + __testlib_fail("random_t::any(const Iter& begin, const Iter& end): range must have positive length"); + return *(begin + next(size)); + } + + /* Random string value by given pattern (see pattern documentation). */ +#ifdef __GNUC__ + __attribute__ ((format (printf, 2, 3))) +#endif + std::string next(const char *format, ...) { + FMT_TO_RESULT(format, format, ptrn); + return next(ptrn); + } + + /* + * Weighted next. If type == 0 than it is usual "next()". + * + * If type = 1, than it returns "max(next(), next())" + * (the number of "max" functions equals to "type"). + * + * If type < 0, than "max" function replaces with "min". + */ + int wnext(int n, int type) { + if (n <= 0) + __testlib_fail("random_t::wnext(int n, int type): n must be positive"); + + if (abs(type) < random_t::lim) { + int result = next(n); + + for (int i = 0; i < +type; i++) + result = __testlib_max(result, next(n)); + + for (int i = 0; i < -type; i++) + result = __testlib_min(result, next(n)); + + return result; + } else { + double p; + + if (type > 0) + p = std::pow(next() + 0.0, 1.0 / (type + 1)); + else + p = 1 - std::pow(next() + 0.0, 1.0 / (-type + 1)); + + return __testlib_crop((int) (double(n) * p), 0, n); + } + } + + /* See wnext(int, int). It uses the same algorithms. */ + long long wnext(long long n, int type) { + if (n <= 0) + __testlib_fail("random_t::wnext(long long n, int type): n must be positive"); + + if (abs(type) < random_t::lim) { + long long result = next(n); + + for (int i = 0; i < +type; i++) + result = __testlib_max(result, next(n)); + + for (int i = 0; i < -type; i++) + result = __testlib_min(result, next(n)); + + return result; + } else { + double p; + + if (type > 0) + p = std::pow(next() + 0.0, 1.0 / (type + 1)); + else + p = 1 - std::pow(next() + 0.0, 1.0 / (-type + 1)); + + return __testlib_crop((long long) (double(n) * p), 0LL, n); + } + } + + /* Returns value in [0, n). See wnext(int, int). It uses the same algorithms. */ + double wnext(double n, int type) { + if (n <= 0) + __testlib_fail("random_t::wnext(double n, int type): n must be positive"); + + if (abs(type) < random_t::lim) { + double result = next(); + + for (int i = 0; i < +type; i++) + result = __testlib_max(result, next()); + + for (int i = 0; i < -type; i++) + result = __testlib_min(result, next()); + + return n * result; + } else { + double p; + + if (type > 0) + p = std::pow(next() + 0.0, 1.0 / (type + 1)); + else + p = 1 - std::pow(next() + 0.0, 1.0 / (-type + 1)); + + return __testlib_crop(n * p, 0.0, n); + } + } + + /* Returns value in [0, 1). See wnext(int, int). It uses the same algorithms. */ + double wnext(int type) { + return wnext(1.0, type); + } + + /* See wnext(int, int). It uses the same algorithms. */ + unsigned int wnext(unsigned int n, int type) { + if (n >= INT_MAX) + __testlib_fail("random_t::wnext(unsigned int n, int type): n must be less INT_MAX"); + return (unsigned int) wnext(int(n), type); + } + + /* See wnext(int, int). It uses the same algorithms. */ + unsigned long long wnext(unsigned long long n, int type) { + if (n >= (unsigned long long) (__TESTLIB_LONGLONG_MAX)) + __testlib_fail("random_t::wnext(unsigned long long n, int type): n must be less LONGLONG_MAX"); + + return (unsigned long long) wnext((long long) (n), type); + } + + /* See wnext(int, int). It uses the same algorithms. */ + long wnext(long n, int type) { + return (long) wnext((long long) (n), type); + } + + /* See wnext(int, int). It uses the same algorithms. */ + unsigned long wnext(unsigned long n, int type) { + if (n >= (unsigned long) (LONG_MAX)) + __testlib_fail("random_t::wnext(unsigned long n, int type): n must be less LONG_MAX"); + + return (unsigned long) wnext((unsigned long long) (n), type); + } + + /* Returns weighted random value in range [from, to]. */ + int wnext(int from, int to, int type) { + if (from > to) + __testlib_fail("random_t::wnext(int from, int to, int type): from can't not exceed to"); + return wnext(to - from + 1, type) + from; + } + + /* Returns weighted random value in range [from, to]. */ + int wnext(unsigned int from, unsigned int to, int type) { + if (from > to) + __testlib_fail("random_t::wnext(unsigned int from, unsigned int to, int type): from can't not exceed to"); + return int(wnext(to - from + 1, type) + from); + } + + /* Returns weighted random value in range [from, to]. */ + long long wnext(long long from, long long to, int type) { + if (from > to) + __testlib_fail("random_t::wnext(long long from, long long to, int type): from can't not exceed to"); + return wnext(to - from + 1, type) + from; + } + + /* Returns weighted random value in range [from, to]. */ + unsigned long long wnext(unsigned long long from, unsigned long long to, int type) { + if (from > to) + __testlib_fail( + "random_t::wnext(unsigned long long from, unsigned long long to, int type): from can't not exceed to"); + return wnext(to - from + 1, type) + from; + } + + /* Returns weighted random value in range [from, to]. */ + long wnext(long from, long to, int type) { + if (from > to) + __testlib_fail("random_t::wnext(long from, long to, int type): from can't not exceed to"); + return wnext(to - from + 1, type) + from; + } + + /* Returns weighted random value in range [from, to]. */ + unsigned long wnext(unsigned long from, unsigned long to, int type) { + if (from > to) + __testlib_fail("random_t::wnext(unsigned long from, unsigned long to, int type): from can't not exceed to"); + return wnext(to - from + 1, type) + from; + } + + /* Returns weighted random double value in range [from, to). */ + double wnext(double from, double to, int type) { + if (from >= to) + __testlib_fail("random_t::wnext(double from, double to, int type): from should be strictly less than to"); + return wnext(to - from, type) + from; + } + + /* Returns weighted random element from container. */ + template + typename Container::value_type wany(const Container &c, int type) { + size_t size = c.size(); + if (size <= 0) + __testlib_fail("random_t::wany(const Container& c, int type): c.size() must be positive"); + return *(c.begin() + wnext(size, type)); + } + + /* Returns weighted random element from iterator range. */ + template + typename Iter::value_type wany(const Iter &begin, const Iter &end, int type) { + int size = int(end - begin); + if (size <= 0) + __testlib_fail( + "random_t::any(const Iter& begin, const Iter& end, int type): range must have positive length"); + return *(begin + wnext(size, type)); + } + + /* Returns random permutation of the given size (values are between `first` and `first`+size-1)*/ + template + std::vector perm(T size, E first) { + if (size < 0) + __testlib_fail("random_t::perm(T size, E first = 0): size must non-negative"); + else if (size == 0) + return std::vector(); + std::vector p(size); + E current = first; + for (T i = 0; i < size; i++) + p[i] = current++; + if (size > 1) + for (T i = 1; i < size; i++) + std::swap(p[i], p[next(i + 1)]); + return p; + } + + /* Returns random permutation of the given size (values are between 0 and size-1)*/ + template + std::vector perm(T size) { + return perm(size, T(0)); + } + + /* Returns `size` unordered (unsorted) distinct numbers between `from` and `to`. */ + template + std::vector distinct(int size, T from, T to) { + std::vector result; + if (size == 0) + return result; + + if (from > to) + __testlib_fail("random_t::distinct expected from <= to"); + + if (size < 0) + __testlib_fail("random_t::distinct expected size >= 0"); + + uint64_t n = to - from + 1; + if (uint64_t(size) > n) + __testlib_fail("random_t::distinct expected size <= to - from + 1"); + + double expected = 0.0; + for (int i = 1; i <= size; i++) + expected += double(n) / double(n - i + 1); + + if (expected < double(n)) { + std::set vals; + while (int(vals.size()) < size) { + T x = T(next(from, to)); + if (vals.insert(x).second) + result.push_back(x); + } + } else { + if (n > 1000000000) + __testlib_fail("random_t::distinct here expected to - from + 1 <= 1000000000"); + std::vector p(perm(int(n), from)); + result.insert(result.end(), p.begin(), p.begin() + size); + } + + return result; + } + + /* Returns `size` unordered (unsorted) distinct numbers between `0` and `upper`-1. */ + template + std::vector distinct(int size, T upper) { + if (size < 0) + __testlib_fail("random_t::distinct expected size >= 0"); + if (size == 0) + return std::vector(); + + if (upper <= 0) + __testlib_fail("random_t::distinct expected upper > 0"); + if (size > upper) + __testlib_fail("random_t::distinct expected size <= upper"); + + return distinct(size, T(0), upper - 1); + } + + /* Returns random (unsorted) partition which is a representation of sum as a sum of integers not less than min_part. */ + template + std::vector partition(int size, T sum, T min_part) { + if (size < 0) + __testlib_fail("random_t::partition: size < 0"); + if (size == 0 && sum != 0) + __testlib_fail("random_t::partition: size == 0 && sum != 0"); + if (min_part * size > sum) + __testlib_fail("random_t::partition: min_part * size > sum"); + if (size == 0 && sum == 0) + return std::vector(); + + T sum_ = sum; + sum -= min_part * size; + + std::vector septums(size); + std::vector d = distinct(size - 1, T(1), T(sum + size - 1)); + for (int i = 0; i + 1 < size; i++) + septums[i + 1] = d[i]; + sort(septums.begin(), septums.end()); + + std::vector result(size); + for (int i = 0; i + 1 < size; i++) + result[i] = septums[i + 1] - septums[i] - 1; + result[size - 1] = sum + size - 1 - septums.back(); + + for (std::size_t i = 0; i < result.size(); i++) + result[i] += min_part; + + T result_sum = 0; + for (std::size_t i = 0; i < result.size(); i++) + result_sum += result[i]; + if (result_sum != sum_) + __testlib_fail("random_t::partition: partition sum is expected to be the given sum"); + + if (*std::min_element(result.begin(), result.end()) < min_part) + __testlib_fail("random_t::partition: partition min is expected to be no less than the given min_part"); + + if (int(result.size()) != size || result.size() != (size_t) size) + __testlib_fail("random_t::partition: partition size is expected to be equal to the given size"); + + return result; + } + + /* Returns random (unsorted) partition which is a representation of sum as a sum of positive integers. */ + template + std::vector partition(int size, T sum) { + return partition(size, sum, T(1)); + } +}; + +const int random_t::lim = 25; +const unsigned long long random_t::multiplier = 0x5DEECE66DLL; +const unsigned long long random_t::addend = 0xBLL; +const unsigned long long random_t::mask = (1LL << 48) - 1; +int random_t::version = -1; + +/* Pattern implementation */ +bool pattern::matches(const std::string &s) const { + return matches(s, 0); +} + +static bool __pattern_isSlash(const std::string &s, size_t pos) { + return s[pos] == '\\'; +} + +#ifdef __GNUC__ +__attribute__((pure)) +#endif +static bool __pattern_isCommandChar(const std::string &s, size_t pos, char value) { + if (pos >= s.length()) + return false; + + int slashes = 0; + + int before = int(pos) - 1; + while (before >= 0 && s[before] == '\\') + before--, slashes++; + + return slashes % 2 == 0 && s[pos] == value; +} + +static char __pattern_getChar(const std::string &s, size_t &pos) { + if (__pattern_isSlash(s, pos)) + pos += 2; + else + pos++; + + return s[pos - 1]; +} + +#ifdef __GNUC__ +__attribute__((pure)) +#endif +static int __pattern_greedyMatch(const std::string &s, size_t pos, const std::vector chars) { + int result = 0; + + while (pos < s.length()) { + char c = s[pos++]; + if (!std::binary_search(chars.begin(), chars.end(), c)) + break; + else + result++; + } + + return result; +} + +std::string pattern::src() const { + return s; +} + +bool pattern::matches(const std::string &s, size_t pos) const { + std::string result; + + if (to > 0) { + int size = __pattern_greedyMatch(s, pos, chars); + if (size < from) + return false; + if (size > to) + size = to; + pos += size; + } + + if (children.size() > 0) { + for (size_t child = 0; child < children.size(); child++) + if (children[child].matches(s, pos)) + return true; + return false; + } else + return pos == s.length(); +} + +std::string pattern::next(random_t &rnd) const { + std::string result; + result.reserve(20); + + if (to == INT_MAX) + __testlib_fail("pattern::next(random_t& rnd): can't process character '*' for generation"); + + if (to > 0) { + int count = rnd.next(to - from + 1) + from; + for (int i = 0; i < count; i++) + result += chars[rnd.next(int(chars.size()))]; + } + + if (children.size() > 0) { + int child = rnd.next(int(children.size())); + result += children[child].next(rnd); + } + + return result; +} + +static void __pattern_scanCounts(const std::string &s, size_t &pos, int &from, int &to) { + if (pos >= s.length()) { + from = to = 1; + return; + } + + if (__pattern_isCommandChar(s, pos, '{')) { + std::vector parts; + std::string part; + + pos++; + + while (pos < s.length() && !__pattern_isCommandChar(s, pos, '}')) { + if (__pattern_isCommandChar(s, pos, ',')) + parts.push_back(part), part = "", pos++; + else + part += __pattern_getChar(s, pos); + } + + if (part != "") + parts.push_back(part); + + if (!__pattern_isCommandChar(s, pos, '}')) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + + pos++; + + if (parts.size() < 1 || parts.size() > 2) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + + std::vector numbers; + + for (size_t i = 0; i < parts.size(); i++) { + if (parts[i].length() == 0) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + int number; + if (std::sscanf(parts[i].c_str(), "%d", &number) != 1) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + numbers.push_back(number); + } + + if (numbers.size() == 1) + from = to = numbers[0]; + else + from = numbers[0], to = numbers[1]; + + if (from > to) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + } else { + if (__pattern_isCommandChar(s, pos, '?')) { + from = 0, to = 1, pos++; + return; + } + + if (__pattern_isCommandChar(s, pos, '*')) { + from = 0, to = INT_MAX, pos++; + return; + } + + if (__pattern_isCommandChar(s, pos, '+')) { + from = 1, to = INT_MAX, pos++; + return; + } + + from = to = 1; + } +} + +static std::vector __pattern_scanCharSet(const std::string &s, size_t &pos) { + if (pos >= s.length()) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + + std::vector result; + + if (__pattern_isCommandChar(s, pos, '[')) { + pos++; + bool negative = __pattern_isCommandChar(s, pos, '^'); + if (negative) + pos++; + + char prev = 0; + + while (pos < s.length() && !__pattern_isCommandChar(s, pos, ']')) { + if (__pattern_isCommandChar(s, pos, '-') && prev != 0) { + pos++; + + if (pos + 1 == s.length() || __pattern_isCommandChar(s, pos, ']')) { + result.push_back(prev); + prev = '-'; + continue; + } + + char next = __pattern_getChar(s, pos); + if (prev > next) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + + for (char c = prev; c != next; c++) + result.push_back(c); + result.push_back(next); + + prev = 0; + } else { + if (prev != 0) + result.push_back(prev); + prev = __pattern_getChar(s, pos); + } + } + + if (prev != 0) + result.push_back(prev); + + if (!__pattern_isCommandChar(s, pos, ']')) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + + pos++; + + if (negative) { + std::sort(result.begin(), result.end()); + std::vector actuals; + for (int code = 0; code < 255; code++) { + char c = char(code); + if (!std::binary_search(result.begin(), result.end(), c)) + actuals.push_back(c); + } + result = actuals; + } + + std::sort(result.begin(), result.end()); + } else + result.push_back(__pattern_getChar(s, pos)); + + return result; +} + +pattern::pattern(std::string s) : s(s), from(0), to(0) { + std::string t; + for (size_t i = 0; i < s.length(); i++) + if (!__pattern_isCommandChar(s, i, ' ')) + t += s[i]; + s = t; + + int opened = 0; + int firstClose = -1; + std::vector seps; + + for (size_t i = 0; i < s.length(); i++) { + if (__pattern_isCommandChar(s, i, '(')) { + opened++; + continue; + } + + if (__pattern_isCommandChar(s, i, ')')) { + opened--; + if (opened == 0 && firstClose == -1) + firstClose = int(i); + continue; + } + + if (opened < 0) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + + if (__pattern_isCommandChar(s, i, '|') && opened == 0) + seps.push_back(int(i)); + } + + if (opened != 0) + __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); + + if (seps.size() == 0 && firstClose + 1 == (int) s.length() + && __pattern_isCommandChar(s, 0, '(') && __pattern_isCommandChar(s, s.length() - 1, ')')) { + children.push_back(pattern(s.substr(1, s.length() - 2))); + } else { + if (seps.size() > 0) { + seps.push_back(int(s.length())); + int last = 0; + + for (size_t i = 0; i < seps.size(); i++) { + children.push_back(pattern(s.substr(last, seps[i] - last))); + last = seps[i] + 1; + } + } else { + size_t pos = 0; + chars = __pattern_scanCharSet(s, pos); + __pattern_scanCounts(s, pos, from, to); + if (pos < s.length()) + children.push_back(pattern(s.substr(pos))); + } + } +} + +/* End of pattern implementation */ + +template +inline bool isEof(C c) { + return c == EOFC; +} + +template +inline bool isEoln(C c) { + return (c == LF || c == CR); +} + +template +inline bool isBlanks(C c) { + return (c == LF || c == CR || c == SPACE || c == TAB); +} + +inline std::string trim(const std::string &s) { + if (s.empty()) + return s; + + int left = 0; + while (left < int(s.length()) && isBlanks(s[left])) + left++; + if (left >= int(s.length())) + return ""; + + int right = int(s.length()) - 1; + while (right >= 0 && isBlanks(s[right])) + right--; + if (right < 0) + return ""; + + return s.substr(left, right - left + 1); +} + +enum TMode { + _input, _output, _answer +}; + +/* Outcomes 6-15 are reserved for future use. */ +enum TResult { + _ok = 0, + _wa = 1, + _pe = 2, + _fail = 3, + _dirt = 4, + _points = 5, + _unexpected_eof = 8, + _partially = 16 +}; + +enum TTestlibMode { + _unknown, _checker, _validator, _generator, _interactor, _scorer +}; + +#define _pc(exitCode) (TResult(_partially + (exitCode))) + +/* Outcomes 6-15 are reserved for future use. */ +const std::string outcomes[] = { + "accepted", + "wrong-answer", + "presentation-error", + "fail", + "fail", +#ifndef PCMS2 + "points", +#else + "relative-scoring", +#endif + "reserved", + "reserved", + "unexpected-eof", + "reserved", + "reserved", + "reserved", + "reserved", + "reserved", + "reserved", + "reserved", + "partially-correct" +}; + +class InputStreamReader { +public: + virtual void setTestCase(int testCase) = 0; + + virtual std::vector getReadChars() = 0; + + virtual int curChar() = 0; + + virtual int nextChar() = 0; + + virtual void skipChar() = 0; + + virtual void unreadChar(int c) = 0; + + virtual std::string getName() = 0; + + virtual bool eof() = 0; + + virtual void close() = 0; + + virtual int getLine() = 0; + + virtual ~InputStreamReader() = 0; +}; + +InputStreamReader::~InputStreamReader() { + // No operations. +} + +class StringInputStreamReader : public InputStreamReader { +private: + std::string s; + size_t pos; + +public: + StringInputStreamReader(const std::string &content) : s(content), pos(0) { + // No operations. + } + + void setTestCase(int) { + __testlib_fail("setTestCase not implemented in StringInputStreamReader"); + } + + std::vector getReadChars() { + __testlib_fail("getReadChars not implemented in StringInputStreamReader"); + } + + int curChar() { + if (pos >= s.length()) + return EOFC; + else + return s[pos]; + } + + int nextChar() { + if (pos >= s.length()) { + pos++; + return EOFC; + } else + return s[pos++]; + } + + void skipChar() { + pos++; + } + + void unreadChar(int c) { + if (pos == 0) + __testlib_fail("StringInputStreamReader::unreadChar(int): pos == 0."); + pos--; + if (pos < s.length()) + s[pos] = char(c); + } + + std::string getName() { + return __testlib_part(s); + } + + int getLine() { + return -1; + } + + bool eof() { + return pos >= s.length(); + } + + void close() { + // No operations. + } +}; + +class FileInputStreamReader : public InputStreamReader { +private: + std::FILE *file; + std::string name; + int line; + std::vector undoChars; + std::vector readChars; + std::vector undoReadChars; + + inline int postprocessGetc(int getcResult) { + if (getcResult != EOF) + return getcResult; + else + return EOFC; + } + + int getc(FILE *file) { + int c; + int rc; + + if (undoChars.empty()) { + c = rc = ::getc(file); + } else { + c = undoChars.back(); + undoChars.pop_back(); + rc = undoReadChars.back(); + undoReadChars.pop_back(); + } + + if (c == LF) + line++; + + readChars.push_back(rc); + return c; + } + + int ungetc(int c/*, FILE* file*/) { + if (!readChars.empty()) { + undoReadChars.push_back(readChars.back()); + readChars.pop_back(); + } + if (c == LF) + line--; + undoChars.push_back(c); + return c; + } + +public: + FileInputStreamReader(std::FILE *file, const std::string &name) : file(file), name(name), line(1) { + // No operations. + } + + void setTestCase(int testCase) { + if (testCase < 0 || testCase > __TESTLIB_MAX_TEST_CASE) + __testlib_fail(format("testCase expected fit in [1,%d], but %d doesn't", __TESTLIB_MAX_TEST_CASE, testCase)); + readChars.push_back(testCase + 256); + } + + std::vector getReadChars() { + return readChars; + } + + int curChar() { + if (feof(file)) + return EOFC; + else { + int c = getc(file); + ungetc(c/*, file*/); + return postprocessGetc(c); + } + } + + int nextChar() { + if (feof(file)) + return EOFC; + else + return postprocessGetc(getc(file)); + } + + void skipChar() { + getc(file); + } + + void unreadChar(int c) { + ungetc(c/*, file*/); + } + + std::string getName() { + return name; + } + + int getLine() { + return line; + } + + bool eof() { + if (NULL == file || feof(file)) + return true; + else { + int c = nextChar(); + if (c == EOFC || (c == EOF && feof(file))) + return true; + unreadChar(c); + return false; + } + } + + void close() { + if (NULL != file) { + fclose(file); + file = NULL; + } + } +}; + +class BufferedFileInputStreamReader : public InputStreamReader { +private: + static const size_t BUFFER_SIZE; + static const size_t MAX_UNREAD_COUNT; + + std::FILE *file; + std::string name; + int line; + + char *buffer; + bool *isEof; + int bufferPos; + size_t bufferSize; + + bool refill() { + if (NULL == file) + __testlib_fail("BufferedFileInputStreamReader: file == NULL (" + getName() + ")"); + + if (bufferPos >= int(bufferSize)) { + size_t readSize = fread( + buffer + MAX_UNREAD_COUNT, + 1, + BUFFER_SIZE - MAX_UNREAD_COUNT, + file + ); + + if (readSize < BUFFER_SIZE - MAX_UNREAD_COUNT + && ferror(file)) + __testlib_fail("BufferedFileInputStreamReader: unable to read (" + getName() + ")"); + + bufferSize = MAX_UNREAD_COUNT + readSize; + bufferPos = int(MAX_UNREAD_COUNT); + std::memset(isEof + MAX_UNREAD_COUNT, 0, sizeof(isEof[0]) * readSize); + + return readSize > 0; + } else + return true; + } + + char increment() { + char c; + if ((c = buffer[bufferPos++]) == LF) + line++; + return c; + } + +public: + BufferedFileInputStreamReader(std::FILE *file, const std::string &name) : file(file), name(name), line(1) { + buffer = new char[BUFFER_SIZE]; + isEof = new bool[BUFFER_SIZE]; + bufferSize = MAX_UNREAD_COUNT; + bufferPos = int(MAX_UNREAD_COUNT); + } + + ~BufferedFileInputStreamReader() { + if (NULL != buffer) { + delete[] buffer; + buffer = NULL; + } + if (NULL != isEof) { + delete[] isEof; + isEof = NULL; + } + } + + void setTestCase(int) { + __testlib_fail("setTestCase not implemented in BufferedFileInputStreamReader"); + } + + std::vector getReadChars() { + __testlib_fail("getReadChars not implemented in BufferedFileInputStreamReader"); + } + + int curChar() { + if (!refill()) + return EOFC; + + return isEof[bufferPos] ? EOFC : buffer[bufferPos]; + } + + int nextChar() { + if (!refill()) + return EOFC; + + return isEof[bufferPos] ? EOFC : increment(); + } + + void skipChar() { + increment(); + } + + void unreadChar(int c) { + bufferPos--; + if (bufferPos < 0) + __testlib_fail("BufferedFileInputStreamReader::unreadChar(int): bufferPos < 0"); + isEof[bufferPos] = (c == EOFC); + buffer[bufferPos] = char(c); + if (c == LF) + line--; + } + + std::string getName() { + return name; + } + + int getLine() { + return line; + } + + bool eof() { + return !refill() || EOFC == curChar(); + } + + void close() { + if (NULL != file) { + fclose(file); + file = NULL; + } + } +}; + +const size_t BufferedFileInputStreamReader::BUFFER_SIZE = 2000000; +const size_t BufferedFileInputStreamReader::MAX_UNREAD_COUNT = BufferedFileInputStreamReader::BUFFER_SIZE / 2; + +/* + * Streams to be used for reading data in checkers or validators. + * Each read*() method moves pointer to the next character after the + * read value. + */ +struct InStream { + /* Do not use them. */ + InStream(); + + ~InStream(); + + /* Wrap std::string with InStream. */ + InStream(const InStream &baseStream, std::string content); + + InputStreamReader *reader; + int lastLine; + + std::string name; + TMode mode; + bool opened; + bool stdfile; + bool strict; + + int wordReserveSize; + std::string _tmpReadToken; + + int readManyIteration; + size_t maxFileSize; + size_t maxTokenLength; + size_t maxMessageLength; + + void init(std::string fileName, TMode mode); + + void init(std::FILE *f, TMode mode); + + void setTestCase(int testCase); + std::vector getReadChars(); + + /* Moves stream pointer to the first non-white-space character or EOF. */ + void skipBlanks(); + + /* Returns current character in the stream. Doesn't remove it from stream. */ + char curChar(); + + /* Moves stream pointer one character forward. */ + void skipChar(); + + /* Returns current character and moves pointer one character forward. */ + char nextChar(); + + /* Returns current character and moves pointer one character forward. */ + char readChar(); + + /* As "readChar()" but ensures that the result is equal to given parameter. */ + char readChar(char c); + + /* As "readChar()" but ensures that the result is equal to the space (code=32). */ + char readSpace(); + + /* Puts back the character into the stream. */ + void unreadChar(char c); + + /* Reopens stream, you should not use it. */ + void reset(std::FILE *file = NULL); + + /* Checks that current position is EOF. If not it doesn't move stream pointer. */ + bool eof(); + + /* Moves pointer to the first non-white-space character and calls "eof()". */ + bool seekEof(); + + /* + * Checks that current position contains EOLN. + * If not it doesn't move stream pointer. + * In strict mode expects "#13#10" for windows or "#10" for other platforms. + */ + bool eoln(); + + /* Moves pointer to the first non-space and non-tab character and calls "eoln()". */ + bool seekEoln(); + + /* Moves stream pointer to the first character of the next line (if exists). */ + void nextLine(); + + /* + * Reads new token. Ignores white-spaces into the non-strict mode + * (strict mode is used in validators usually). + */ + std::string readWord(); + + /* The same as "readWord()", it is preffered to use "readToken()". */ + std::string readToken(); + + /* The same as "readWord()", but ensures that token matches to given pattern. */ + std::string readWord(const std::string &ptrn, const std::string &variableName = ""); + + std::string readWord(const pattern &p, const std::string &variableName = ""); + + std::vector + readWords(int size, const std::string &ptrn, const std::string &variablesName = "", int indexBase = 1); + + std::vector + readWords(int size, const pattern &p, const std::string &variablesName = "", int indexBase = 1); + + std::vector readWords(int size, int indexBase = 1); + + /* The same as "readToken()", but ensures that token matches to given pattern. */ + std::string readToken(const std::string &ptrn, const std::string &variableName = ""); + + std::string readToken(const pattern &p, const std::string &variableName = ""); + + std::vector + readTokens(int size, const std::string &ptrn, const std::string &variablesName = "", int indexBase = 1); + + std::vector + readTokens(int size, const pattern &p, const std::string &variablesName = "", int indexBase = 1); + + std::vector readTokens(int size, int indexBase = 1); + + void readWordTo(std::string &result); + + void readWordTo(std::string &result, const pattern &p, const std::string &variableName = ""); + + void readWordTo(std::string &result, const std::string &ptrn, const std::string &variableName = ""); + + void readTokenTo(std::string &result); + + void readTokenTo(std::string &result, const pattern &p, const std::string &variableName = ""); + + void readTokenTo(std::string &result, const std::string &ptrn, const std::string &variableName = ""); + + /* + * Reads new long long value. Ignores white-spaces into the non-strict mode + * (strict mode is used in validators usually). + */ + long long readLong(); + + unsigned long long readUnsignedLong(); + + /* + * Reads new int. Ignores white-spaces into the non-strict mode + * (strict mode is used in validators usually). + */ + int readInteger(); + + /* + * Reads new int. Ignores white-spaces into the non-strict mode + * (strict mode is used in validators usually). + */ + int readInt(); + + /* As "readLong()" but ensures that value in the range [minv,maxv]. */ + long long readLong(long long minv, long long maxv, const std::string &variableName = ""); + + /* Reads space-separated sequence of long longs. */ + std::vector + readLongs(int size, long long minv, long long maxv, const std::string &variablesName = "", int indexBase = 1); + + /* Reads space-separated sequence of long longs. */ + std::vector readLongs(int size, int indexBase = 1); + + unsigned long long + readUnsignedLong(unsigned long long minv, unsigned long long maxv, const std::string &variableName = ""); + + std::vector + readUnsignedLongs(int size, unsigned long long minv, unsigned long long maxv, const std::string &variablesName = "", + int indexBase = 1); + + std::vector readUnsignedLongs(int size, int indexBase = 1); + + unsigned long long readLong(unsigned long long minv, unsigned long long maxv, const std::string &variableName = ""); + + std::vector + readLongs(int size, unsigned long long minv, unsigned long long maxv, const std::string &variablesName = "", + int indexBase = 1); + + /* As "readInteger()" but ensures that value in the range [minv,maxv]. */ + int readInteger(int minv, int maxv, const std::string &variableName = ""); + + /* As "readInt()" but ensures that value in the range [minv,maxv]. */ + int readInt(int minv, int maxv, const std::string &variableName = ""); + + /* Reads space-separated sequence of integers. */ + std::vector + readIntegers(int size, int minv, int maxv, const std::string &variablesName = "", int indexBase = 1); + + /* Reads space-separated sequence of integers. */ + std::vector readIntegers(int size, int indexBase = 1); + + /* Reads space-separated sequence of integers. */ + std::vector readInts(int size, int minv, int maxv, const std::string &variablesName = "", int indexBase = 1); + + /* Reads space-separated sequence of integers. */ + std::vector readInts(int size, int indexBase = 1); + + /* + * Reads new double. Ignores white-spaces into the non-strict mode + * (strict mode is used in validators usually). + */ + double readReal(); + + /* + * Reads new double. Ignores white-spaces into the non-strict mode + * (strict mode is used in validators usually). + */ + double readDouble(); + + /* As "readReal()" but ensures that value in the range [minv,maxv]. */ + double readReal(double minv, double maxv, const std::string &variableName = ""); + + std::vector + readReals(int size, double minv, double maxv, const std::string &variablesName = "", int indexBase = 1); + + std::vector readReals(int size, int indexBase = 1); + + /* As "readDouble()" but ensures that value in the range [minv,maxv]. */ + double readDouble(double minv, double maxv, const std::string &variableName = ""); + + std::vector + readDoubles(int size, double minv, double maxv, const std::string &variablesName = "", int indexBase = 1); + + std::vector readDoubles(int size, int indexBase = 1); + + /* + * As "readReal()" but ensures that value in the range [minv,maxv] and + * number of digit after the decimal point is in range [minAfterPointDigitCount,maxAfterPointDigitCount] + * and number is in the form "[-]digit(s)[.digit(s)]". + */ + double readStrictReal(double minv, double maxv, + int minAfterPointDigitCount, int maxAfterPointDigitCount, + const std::string &variableName = ""); + + std::vector readStrictReals(int size, double minv, double maxv, + int minAfterPointDigitCount, int maxAfterPointDigitCount, + const std::string &variablesName = "", int indexBase = 1); + + /* + * As "readDouble()" but ensures that value in the range [minv,maxv] and + * number of digit after the decimal point is in range [minAfterPointDigitCount,maxAfterPointDigitCount] + * and number is in the form "[-]digit(s)[.digit(s)]". + */ + double readStrictDouble(double minv, double maxv, + int minAfterPointDigitCount, int maxAfterPointDigitCount, + const std::string &variableName = ""); + + std::vector readStrictDoubles(int size, double minv, double maxv, + int minAfterPointDigitCount, int maxAfterPointDigitCount, + const std::string &variablesName = "", int indexBase = 1); + + /* As readLine(). */ + std::string readString(); + + /* Read many lines. */ + std::vector readStrings(int size, int indexBase = 1); + + /* See readLine(). */ + void readStringTo(std::string &result); + + /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */ + std::string readString(const pattern &p, const std::string &variableName = ""); + + /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */ + std::string readString(const std::string &ptrn, const std::string &variableName = ""); + + /* Read many lines. */ + std::vector + readStrings(int size, const pattern &p, const std::string &variableName = "", int indexBase = 1); + + /* Read many lines. */ + std::vector + readStrings(int size, const std::string &ptrn, const std::string &variableName = "", int indexBase = 1); + + /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */ + void readStringTo(std::string &result, const pattern &p, const std::string &variableName = ""); + + /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */ + void readStringTo(std::string &result, const std::string &ptrn, const std::string &variableName = ""); + + /* + * Reads line from the current position to EOLN or EOF. Moves stream pointer to + * the first character of the new line (if possible). + */ + std::string readLine(); + + /* Read many lines. */ + std::vector readLines(int size, int indexBase = 1); + + /* See readLine(). */ + void readLineTo(std::string &result); + + /* The same as "readLine()", but ensures that line matches to the given pattern. */ + std::string readLine(const pattern &p, const std::string &variableName = ""); + + /* The same as "readLine()", but ensures that line matches to the given pattern. */ + std::string readLine(const std::string &ptrn, const std::string &variableName = ""); + + /* Read many lines. */ + std::vector + readLines(int size, const pattern &p, const std::string &variableName = "", int indexBase = 1); + + /* Read many lines. */ + std::vector + readLines(int size, const std::string &ptrn, const std::string &variableName = "", int indexBase = 1); + + /* The same as "readLine()", but ensures that line matches to the given pattern. */ + void readLineTo(std::string &result, const pattern &p, const std::string &variableName = ""); + + /* The same as "readLine()", but ensures that line matches to the given pattern. */ + void readLineTo(std::string &result, const std::string &ptrn, const std::string &variableName = ""); + + /* Reads EOLN or fails. Use it in validators. Calls "eoln()" method internally. */ + void readEoln(); + + /* Reads EOF or fails. Use it in validators. Calls "eof()" method internally. */ + void readEof(); + + /* + * Quit-functions aborts program with and : + * input/answer streams replace any result to FAIL. + */ + NORETURN void quit(TResult result, const char *msg); + /* + * Quit-functions aborts program with and : + * input/answer streams replace any result to FAIL. + */ + NORETURN void quitf(TResult result, const char *msg, ...); + + /* + * Quit-functions aborts program with and : + * input/answer streams replace any result to FAIL. + */ + void quitif(bool condition, TResult result, const char *msg, ...); + /* + * Quit-functions aborts program with and : + * input/answer streams replace any result to FAIL. + */ + NORETURN void quits(TResult result, std::string msg); + + /* + * Checks condition and aborts a program if codition is false. + * Returns _wa for ouf and _fail on any other streams. + */ +#ifdef __GNUC__ + __attribute__ ((format (printf, 3, 4))) +#endif + void ensuref(bool cond, const char *format, ...); + + void __testlib_ensure(bool cond, std::string message); + + void close(); + + const static int NO_INDEX = INT_MAX; + const static char OPEN_BRACKET = char(11); + const static char CLOSE_BRACKET = char(17); + + const static WORD LightGray = 0x07; + const static WORD LightRed = 0x0c; + const static WORD LightCyan = 0x0b; + const static WORD LightGreen = 0x0a; + const static WORD LightYellow = 0x0e; + + static void textColor(WORD color); + + static void quitscr(WORD color, const char *msg); + + static void quitscrS(WORD color, std::string msg); + + void xmlSafeWrite(std::FILE *file, const char *msg); + + /* Skips UTF-8 Byte Order Mark. */ + void skipBom(); + +private: + InStream(const InStream &); + + InStream &operator=(const InStream &); +}; + +InStream inf; +InStream ouf; +InStream ans; +bool appesMode; +std::string resultName; +std::string checkerName = "untitled checker"; +random_t rnd; +TTestlibMode testlibMode = _unknown; +double __testlib_points = std::numeric_limits::infinity(); + +struct ValidatorBoundsHit { + static const double EPS; + bool minHit; + bool maxHit; + + ValidatorBoundsHit(bool minHit = false, bool maxHit = false) : minHit(minHit), maxHit(maxHit) { + }; + + ValidatorBoundsHit merge(const ValidatorBoundsHit &validatorBoundsHit) { + return ValidatorBoundsHit( + __testlib_max(minHit, validatorBoundsHit.minHit), + __testlib_max(maxHit, validatorBoundsHit.maxHit) + ); + } +}; + +const double ValidatorBoundsHit::EPS = 1E-12; + +class Validator { +private: + const static std::string TEST_MARKUP_HEADER; + const static std::string TEST_CASE_OPEN_TAG; + const static std::string TEST_CASE_CLOSE_TAG; + + bool _initialized; + std::string _testset; + std::string _group; + + std::string _testOverviewLogFileName; + std::string _testMarkupFileName; + int _testCase = -1; + std::string _testCaseFileName; + + std::map _boundsHitByVariableName; + std::set _features; + std::set _hitFeatures; + + bool isVariableNameBoundsAnalyzable(const std::string &variableName) { + for (size_t i = 0; i < variableName.length(); i++) + if ((variableName[i] >= '0' && variableName[i] <= '9') || variableName[i] < ' ') + return false; + return true; + } + + bool isFeatureNameAnalyzable(const std::string &featureName) { + for (size_t i = 0; i < featureName.length(); i++) + if (featureName[i] < ' ') + return false; + return true; + } + +public: + Validator() : _initialized(false), _testset("tests"), _group() { + } + + void initialize() { + _initialized = true; + } + + std::string testset() const { + if (!_initialized) + __testlib_fail("Validator should be initialized with registerValidation(argc, argv) instead of registerValidation() to support validator.testset()"); + return _testset; + } + + std::string group() const { + if (!_initialized) + __testlib_fail("Validator should be initialized with registerValidation(argc, argv) instead of registerValidation() to support validator.group()"); + return _group; + } + + std::string testOverviewLogFileName() const { + return _testOverviewLogFileName; + } + + std::string testMarkupFileName() const { + return _testMarkupFileName; + } + + int testCase() const { + return _testCase; + } + + std::string testCaseFileName() const { + return _testCaseFileName; + } + + void setTestset(const char *const testset) { + _testset = testset; + } + + void setGroup(const char *const group) { + _group = group; + } + + void setTestOverviewLogFileName(const char *const testOverviewLogFileName) { + _testOverviewLogFileName = testOverviewLogFileName; + } + + void setTestMarkupFileName(const char *const testMarkupFileName) { + _testMarkupFileName = testMarkupFileName; + } + + void setTestCase(int testCase) { + _testCase = testCase; + } + + void setTestCaseFileName(const char *const testCaseFileName) { + _testCaseFileName = testCaseFileName; + } + + void addBoundsHit(const std::string &variableName, ValidatorBoundsHit boundsHit) { + if (isVariableNameBoundsAnalyzable(variableName)) { + _boundsHitByVariableName[variableName] + = boundsHit.merge(_boundsHitByVariableName[variableName]); + } + } + + std::string getBoundsHitLog() { + std::string result; + for (std::map::iterator i = _boundsHitByVariableName.begin(); + i != _boundsHitByVariableName.end(); + i++) { + result += "\"" + i->first + "\":"; + if (i->second.minHit) + result += " min-value-hit"; + if (i->second.maxHit) + result += " max-value-hit"; + result += "\n"; + } + return result; + } + + std::string getFeaturesLog() { + std::string result; + for (std::set::iterator i = _features.begin(); + i != _features.end(); + i++) { + result += "feature \"" + *i + "\":"; + if (_hitFeatures.count(*i)) + result += " hit"; + result += "\n"; + } + return result; + } + + void writeTestOverviewLog() { + if (!_testOverviewLogFileName.empty()) { + std::string fileName(_testOverviewLogFileName); + _testOverviewLogFileName = ""; + FILE *testOverviewLogFile = fopen(fileName.c_str(), "w"); + if (NULL == testOverviewLogFile) + __testlib_fail("Validator::writeTestOverviewLog: can't write test overview log to (" + fileName + ")"); + fprintf(testOverviewLogFile, "%s%s", getBoundsHitLog().c_str(), getFeaturesLog().c_str()); + if (fclose(testOverviewLogFile)) + __testlib_fail( + "Validator::writeTestOverviewLog: can't close test overview log file (" + fileName + ")"); + } + } + + void writeTestMarkup() { + if (!_testMarkupFileName.empty()) { + std::vector readChars = inf.getReadChars(); + if (!readChars.empty()) { + std::string markup(TEST_MARKUP_HEADER); + for (size_t i = 0; i < readChars.size(); i++) { + int c = readChars[i]; + if (i + 1 == readChars.size() && c == -1) + continue; + if (c <= 256) { + char cc = char(c); + if (cc == '\\' || cc == '!') + markup += '\\'; + markup += cc; + } else { + markup += TEST_CASE_OPEN_TAG; + markup += toString(c - 256); + markup += TEST_CASE_CLOSE_TAG; + } + } + FILE* f; + bool standard_file = false; + if (_testMarkupFileName == "stdout") + f = stdout, standard_file = true; + else if (_testMarkupFileName == "stderr") + f = stderr, standard_file = true; + else { + f = fopen(_testMarkupFileName.c_str(), "wb"); + if (NULL == f) + __testlib_fail("Validator::writeTestMarkup: can't write test markup to (" + _testMarkupFileName + ")"); + } + std::fprintf(f, "%s", markup.c_str()); + std::fflush(f); + if (!standard_file) + if (std::fclose(f)) + __testlib_fail("Validator::writeTestMarkup: can't close test markup file (" + _testCaseFileName + ")"); + } + } + } + + void writeTestCase() { + if (_testCase > 0) { + std::vector readChars = inf.getReadChars(); + if (!readChars.empty()) { + std::string content, testCaseContent; + bool matchedTestCase = false; + for (size_t i = 0; i < readChars.size(); i++) { + int c = readChars[i]; + if (i + 1 == readChars.size() && c == -1) + continue; + if (c <= 256) + content += char(c); + else { + if (matchedTestCase) { + testCaseContent = content; + matchedTestCase = false; + } + content = ""; + int testCase = c - 256; + if (testCase == _testCase) + matchedTestCase = true; + } + } + if (matchedTestCase) + testCaseContent = content; + + if (!testCaseContent.empty()) { + FILE* f; + bool standard_file = false; + if (_testCaseFileName.empty() || _testCaseFileName == "stdout") + f = stdout, standard_file = true; + else if (_testCaseFileName == "stderr") + f = stderr, standard_file = true; + else { + f = fopen(_testCaseFileName.c_str(), "wb"); + if (NULL == f) + __testlib_fail("Validator::writeTestCase: can't write test case to (" + _testCaseFileName + ")"); + } + std::fprintf(f, "%s", testCaseContent.c_str()); + std::fflush(f); + if (!standard_file) + if (std::fclose(f)) + __testlib_fail("Validator::writeTestCase: can't close test case file (" + _testCaseFileName + ")"); + } + } + } + } + + void addFeature(const std::string &feature) { + if (_features.count(feature)) + __testlib_fail("Feature " + feature + " registered twice."); + if (!isFeatureNameAnalyzable(feature)) + __testlib_fail("Feature name '" + feature + "' contains restricted characters."); + + _features.insert(feature); + } + + void feature(const std::string &feature) { + if (!isFeatureNameAnalyzable(feature)) + __testlib_fail("Feature name '" + feature + "' contains restricted characters."); + + if (!_features.count(feature)) + __testlib_fail("Feature " + feature + " didn't registered via addFeature(feature)."); + + _hitFeatures.insert(feature); + } +} validator; + +const std::string Validator::TEST_MARKUP_HEADER = "MU\xF3\x01"; +const std::string Validator::TEST_CASE_OPEN_TAG = "!c"; +const std::string Validator::TEST_CASE_CLOSE_TAG = ";"; + +struct TestlibFinalizeGuard { + static bool alive; + static bool registered; + + int quitCount, readEofCount; + + TestlibFinalizeGuard() : quitCount(0), readEofCount(0) { + // No operations. + } + + ~TestlibFinalizeGuard() { + bool _alive = alive; + alive = false; + + if (_alive) { + if (testlibMode == _checker && quitCount == 0) + __testlib_fail("Checker must end with quit or quitf call."); + + if (testlibMode == _validator && readEofCount == 0 && quitCount == 0) + __testlib_fail("Validator must end with readEof call."); + + /* opts */ + autoEnsureNoUnusedOpts(); + + if (!registered) + __testlib_fail("Call register-function in the first line of the main (registerTestlibCmd or other similar)"); + } + + if (__testlib_exitCode == 0) { + validator.writeTestOverviewLog(); + validator.writeTestMarkup(); + validator.writeTestCase(); + } + } + +private: + /* opts */ + void autoEnsureNoUnusedOpts(); +}; + +bool TestlibFinalizeGuard::alive = true; +bool TestlibFinalizeGuard::registered = false; +extern TestlibFinalizeGuard testlibFinalizeGuard; + +/* + * Call it to disable checks on finalization. + */ +void disableFinalizeGuard() { + TestlibFinalizeGuard::alive = false; +} + +/* Interactor streams. + */ +std::fstream tout; + +/* implementation + */ + +InStream::InStream() { + reader = NULL; + lastLine = -1; + opened = false; + name = ""; + mode = _input; + strict = false; + stdfile = false; + wordReserveSize = 4; + readManyIteration = NO_INDEX; + maxFileSize = 128 * 1024 * 1024; // 128MB. + maxTokenLength = 32 * 1024 * 1024; // 32MB. + maxMessageLength = 32000; +} + +InStream::InStream(const InStream &baseStream, std::string content) { + reader = new StringInputStreamReader(content); + lastLine = -1; + opened = true; + strict = baseStream.strict; + stdfile = false; + mode = baseStream.mode; + name = "based on " + baseStream.name; + readManyIteration = NO_INDEX; + maxFileSize = 128 * 1024 * 1024; // 128MB. + maxTokenLength = 32 * 1024 * 1024; // 32MB. + maxMessageLength = 32000; +} + +InStream::~InStream() { + if (NULL != reader) { + reader->close(); + delete reader; + reader = NULL; + } +} + +void InStream::setTestCase(int testCase) { + if (testlibMode != _validator || mode != _input || !stdfile || this != &inf) + __testlib_fail("InStream::setTestCase can be used only for inf in validator-mode." + " Actually, prefer setTestCase function instead of InStream member"); + reader->setTestCase(testCase); +} + +std::vector InStream::getReadChars() { + if (testlibMode != _validator || mode != _input || !stdfile || this != &inf) + __testlib_fail("InStream::getReadChars can be used only for inf in validator-mode."); + return reader == NULL ? std::vector() : reader->getReadChars(); +} + +void setTestCase(int testCase) { + static bool first_run = true; + static bool zero_based = false; + + if (first_run && testCase == 0) + zero_based = true; + + if (zero_based) + testCase++; + + __testlib_hasTestCase = true; + __testlib_testCase = testCase; + + if (testlibMode == _validator) + inf.setTestCase(testCase); + + first_run = false; +} + +#ifdef __GNUC__ +__attribute__((const)) +#endif +int resultExitCode(TResult r) { + if (r == _ok) + return OK_EXIT_CODE; + if (r == _wa) + return WA_EXIT_CODE; + if (r == _pe) + return PE_EXIT_CODE; + if (r == _fail) + return FAIL_EXIT_CODE; + if (r == _dirt) + return DIRT_EXIT_CODE; + if (r == _points) + return POINTS_EXIT_CODE; + if (r == _unexpected_eof) +#ifdef ENABLE_UNEXPECTED_EOF + return UNEXPECTED_EOF_EXIT_CODE; +#else + return PE_EXIT_CODE; +#endif + if (r >= _partially) + return PC_BASE_EXIT_CODE + (r - _partially); + return FAIL_EXIT_CODE; +} + +void InStream::textColor( +#if !(defined(ON_WINDOWS) && (!defined(_MSC_VER) || _MSC_VER > 1400)) && defined(__GNUC__) + __attribute__((unused)) +#endif + WORD color +) { +#if defined(ON_WINDOWS) && (!defined(_MSC_VER) || _MSC_VER > 1400) + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(handle, color); +#endif +#if !defined(ON_WINDOWS) && defined(__GNUC__) + if (isatty(2)) + { + switch (color) + { + case LightRed: + fprintf(stderr, "\033[1;31m"); + break; + case LightCyan: + fprintf(stderr, "\033[1;36m"); + break; + case LightGreen: + fprintf(stderr, "\033[1;32m"); + break; + case LightYellow: + fprintf(stderr, "\033[1;33m"); + break; + case LightGray: + default: + fprintf(stderr, "\033[0m"); + } + } +#endif +} + +#ifdef TESTLIB_THROW_EXIT_EXCEPTION_INSTEAD_OF_EXIT +class exit_exception: public std::exception { +private: + int exitCode; +public: + exit_exception(int exitCode): exitCode(exitCode) {} + int getExitCode() { return exitCode; } +}; +#endif + +NORETURN void halt(int exitCode) { +#ifdef FOOTER + InStream::textColor(InStream::LightGray); + std::fprintf(stderr, "Checker: \"%s\"\n", checkerName.c_str()); + std::fprintf(stderr, "Exit code: %d\n", exitCode); + InStream::textColor(InStream::LightGray); +#endif + __testlib_exitCode = exitCode; +#ifdef TESTLIB_THROW_EXIT_EXCEPTION_INSTEAD_OF_EXIT + throw exit_exception(exitCode); +#endif + std::exit(exitCode); +} + +static bool __testlib_shouldCheckDirt(TResult result) { + return result == _ok || result == _points || result >= _partially; +} + +static std::string __testlib_appendMessage(const std::string &message, const std::string &extra) { + int openPos = -1, closePos = -1; + for (size_t i = 0; i < message.length(); i++) { + if (message[i] == InStream::OPEN_BRACKET) { + if (openPos == -1) + openPos = int(i); + else + openPos = INT_MAX; + } + if (message[i] == InStream::CLOSE_BRACKET) { + if (closePos == -1) + closePos = int(i); + else + closePos = INT_MAX; + } + } + if (openPos != -1 && openPos != INT_MAX + && closePos != -1 && closePos != INT_MAX + && openPos < closePos) { + size_t index = message.find(extra, openPos); + if (index == std::string::npos || int(index) >= closePos) { + std::string result(message); + result.insert(closePos, ", " + extra); + return result; + } + return message; + } + + return message + " " + InStream::OPEN_BRACKET + extra + InStream::CLOSE_BRACKET; +} + +static std::string __testlib_toPrintableMessage(const std::string &message) { + int openPos = -1, closePos = -1; + for (size_t i = 0; i < message.length(); i++) { + if (message[i] == InStream::OPEN_BRACKET) { + if (openPos == -1) + openPos = int(i); + else + openPos = INT_MAX; + } + if (message[i] == InStream::CLOSE_BRACKET) { + if (closePos == -1) + closePos = int(i); + else + closePos = INT_MAX; + } + } + if (openPos != -1 && openPos != INT_MAX + && closePos != -1 && closePos != INT_MAX + && openPos < closePos) { + std::string result(message); + result[openPos] = '('; + result[closePos] = ')'; + return result; + } + + return message; +} + +NORETURN void InStream::quit(TResult result, const char *msg) { + if (TestlibFinalizeGuard::alive) + testlibFinalizeGuard.quitCount++; + + std::string message(msg); + message = trim(message); + + if (__testlib_hasTestCase) { + if (result != _ok) + message = __testlib_appendMessage(message, "test case " + vtos(__testlib_testCase)); + else { + if (__testlib_testCase == 1) + message = __testlib_appendMessage(message, vtos(__testlib_testCase) + " test case"); + else + message = __testlib_appendMessage(message, vtos(__testlib_testCase) + " test cases"); + } + } + + // You can change maxMessageLength. + // Example: 'inf.maxMessageLength = 1024 * 1024;'. + if (message.length() > maxMessageLength) { + std::string warn = "message length exceeds " + vtos(maxMessageLength) + + ", the message is truncated: "; + message = warn + message.substr(0, maxMessageLength - warn.length()); + } + +#ifndef ENABLE_UNEXPECTED_EOF + if (result == _unexpected_eof) + result = _pe; +#endif + + if (testlibMode == _scorer && result != _fail) + quits(_fail, "Scorer should return points only. Don't use a quit function."); + + if (mode != _output && result != _fail) { + if (mode == _input && testlibMode == _validator && lastLine != -1) + quits(_fail, __testlib_appendMessage(__testlib_appendMessage(message, name), "line " + vtos(lastLine))); + else + quits(_fail, __testlib_appendMessage(message, name)); + } + + std::FILE *resultFile; + std::string errorName; + + if (__testlib_shouldCheckDirt(result)) { + if (testlibMode != _interactor && !ouf.seekEof()) + quit(_dirt, "Extra information in the output file"); + } + + int pctype = result - _partially; + bool isPartial = false; + + switch (result) { + case _ok: + errorName = "ok "; + quitscrS(LightGreen, errorName); + break; + case _wa: + errorName = "wrong answer "; + quitscrS(LightRed, errorName); + break; + case _pe: + errorName = "wrong output format "; + quitscrS(LightRed, errorName); + break; + case _fail: + errorName = "FAIL "; + quitscrS(LightRed, errorName); + break; + case _dirt: + errorName = "wrong output format "; + quitscrS(LightCyan, errorName); + result = _pe; + break; + case _points: + errorName = "points "; + quitscrS(LightYellow, errorName); + break; + case _unexpected_eof: + errorName = "unexpected eof "; + quitscrS(LightCyan, errorName); + break; + default: + if (result >= _partially) { + errorName = format("partially correct (%d) ", pctype); + isPartial = true; + quitscrS(LightYellow, errorName); + } else + quit(_fail, "What is the code ??? "); + } + + if (resultName != "") { + resultFile = std::fopen(resultName.c_str(), "w"); + if (resultFile == NULL) { + resultName = ""; + quit(_fail, "Can not write to the result file"); + } + if (appesMode) { + std::fprintf(resultFile, ""); + if (isPartial) + std::fprintf(resultFile, "", + outcomes[(int) _partially].c_str(), pctype); + else { + if (result != _points) + std::fprintf(resultFile, "", outcomes[(int) result].c_str()); + else { + if (__testlib_points == std::numeric_limits::infinity()) + quit(_fail, "Expected points, but infinity found"); + std::string stringPoints = removeDoubleTrailingZeroes(format("%.10f", __testlib_points)); + std::fprintf(resultFile, "", + outcomes[(int) result].c_str(), stringPoints.c_str()); + } + } + xmlSafeWrite(resultFile, __testlib_toPrintableMessage(message).c_str()); + std::fprintf(resultFile, "\n"); + } else + std::fprintf(resultFile, "%s", __testlib_toPrintableMessage(message).c_str()); + if (NULL == resultFile || fclose(resultFile) != 0) { + resultName = ""; + quit(_fail, "Can not write to the result file"); + } + } + + quitscr(LightGray, __testlib_toPrintableMessage(message).c_str()); + std::fprintf(stderr, "\n"); + + inf.close(); + ouf.close(); + ans.close(); + if (tout.is_open()) + tout.close(); + + textColor(LightGray); + + if (resultName != "") + std::fprintf(stderr, "See file to check exit message\n"); + + halt(resultExitCode(result)); +} + +#ifdef __GNUC__ +__attribute__ ((format (printf, 3, 4))) +#endif +NORETURN void InStream::quitf(TResult result, const char *msg, ...) { + FMT_TO_RESULT(msg, msg, message); + InStream::quit(result, message.c_str()); +} + +#ifdef __GNUC__ +__attribute__ ((format (printf, 4, 5))) +#endif +void InStream::quitif(bool condition, TResult result, const char *msg, ...) { + if (condition) { + FMT_TO_RESULT(msg, msg, message); + InStream::quit(result, message.c_str()); + } +} + +NORETURN void InStream::quits(TResult result, std::string msg) { + InStream::quit(result, msg.c_str()); +} + +void InStream::xmlSafeWrite(std::FILE *file, const char *msg) { + size_t lmsg = strlen(msg); + for (size_t i = 0; i < lmsg; i++) { + if (msg[i] == '&') { + std::fprintf(file, "%s", "&"); + continue; + } + if (msg[i] == '<') { + std::fprintf(file, "%s", "<"); + continue; + } + if (msg[i] == '>') { + std::fprintf(file, "%s", ">"); + continue; + } + if (msg[i] == '"') { + std::fprintf(file, "%s", """); + continue; + } + if (0 <= msg[i] && msg[i] <= 31) { + std::fprintf(file, "%c", '.'); + continue; + } + std::fprintf(file, "%c", msg[i]); + } +} + +void InStream::quitscrS(WORD color, std::string msg) { + quitscr(color, msg.c_str()); +} + +void InStream::quitscr(WORD color, const char *msg) { + if (resultName == "") { + textColor(color); + std::fprintf(stderr, "%s", msg); + textColor(LightGray); + } +} + +void InStream::reset(std::FILE *file) { + if (opened && stdfile) + quit(_fail, "Can't reset standard handle"); + + if (opened) + close(); + + if (!stdfile && NULL == file) + if (NULL == (file = std::fopen(name.c_str(), "rb"))) { + if (mode == _output) + quits(_pe, std::string("Output file not found: \"") + name + "\""); + + if (mode == _answer) + quits(_fail, std::string("Answer file not found: \"") + name + "\""); + } + + if (NULL != file) { + opened = true; + __testlib_set_binary(file); + + if (stdfile) + reader = new FileInputStreamReader(file, name); + else + reader = new BufferedFileInputStreamReader(file, name); + } else { + opened = false; + reader = NULL; + } +} + +void InStream::init(std::string fileName, TMode mode) { + opened = false; + name = fileName; + stdfile = false; + this->mode = mode; + + std::ifstream stream; + stream.open(fileName.c_str(), std::ios::in); + if (stream.is_open()) { + std::streampos start = stream.tellg(); + stream.seekg(0, std::ios::end); + std::streampos end = stream.tellg(); + size_t fileSize = size_t(end - start); + stream.close(); + + // You can change maxFileSize. + // Example: 'inf.maxFileSize = 256 * 1024 * 1024;'. + if (fileSize > maxFileSize) + quitf(_pe, "File size exceeds %d bytes, size is %d", int(maxFileSize), int(fileSize)); + } + + reset(); + skipBom(); +} + +void InStream::init(std::FILE *f, TMode mode) { + opened = false; + name = "untitled"; + this->mode = mode; + + if (f == stdin) + name = "stdin", stdfile = true; + if (f == stdout) + name = "stdout", stdfile = true; + if (f == stderr) + name = "stderr", stdfile = true; + + reset(f); + skipBom(); +} + +void InStream::skipBom() { + const std::string utf8Bom = "\xEF\xBB\xBF"; + size_t index = 0; + while (index < utf8Bom.size() && curChar() == utf8Bom[index]) { + index++; + skipChar(); + } + if (index < utf8Bom.size()) { + while (index != 0) { + unreadChar(utf8Bom[index - 1]); + index--; + } + } +} + +char InStream::curChar() { + return char(reader->curChar()); +} + +char InStream::nextChar() { + return char(reader->nextChar()); +} + +char InStream::readChar() { + return nextChar(); +} + +char InStream::readChar(char c) { + lastLine = reader->getLine(); + char found = readChar(); + if (c != found) { + if (!isEoln(found)) + quit(_pe, ("Unexpected character '" + std::string(1, found) + "', but '" + std::string(1, c) + + "' expected").c_str()); + else + quit(_pe, ("Unexpected character " + ("#" + vtos(int(found))) + ", but '" + std::string(1, c) + + "' expected").c_str()); + } + return found; +} + +char InStream::readSpace() { + return readChar(' '); +} + +void InStream::unreadChar(char c) { + reader->unreadChar(c); +} + +void InStream::skipChar() { + reader->skipChar(); +} + +void InStream::skipBlanks() { + while (isBlanks(reader->curChar())) + reader->skipChar(); +} + +std::string InStream::readWord() { + readWordTo(_tmpReadToken); + return _tmpReadToken; +} + +void InStream::readWordTo(std::string &result) { + if (!strict) + skipBlanks(); + + lastLine = reader->getLine(); + int cur = reader->nextChar(); + + if (cur == EOFC) + quit(_unexpected_eof, "Unexpected end of file - token expected"); + + if (isBlanks(cur)) + quit(_pe, "Unexpected white-space - token expected"); + + result.clear(); + + while (!(isBlanks(cur) || cur == EOFC)) { + result += char(cur); + + // You can change maxTokenLength. + // Example: 'inf.maxTokenLength = 128 * 1024 * 1024;'. + if (result.length() > maxTokenLength) + quitf(_pe, "Length of token exceeds %d, token is '%s...'", int(maxTokenLength), + __testlib_part(result).c_str()); + + cur = reader->nextChar(); + } + + reader->unreadChar(cur); + + if (result.length() == 0) + quit(_unexpected_eof, "Unexpected end of file or white-space - token expected"); +} + +std::string InStream::readToken() { + return readWord(); +} + +void InStream::readTokenTo(std::string &result) { + readWordTo(result); +} + +static std::string __testlib_part(const std::string &s) { + std::string t; + for (size_t i = 0; i < s.length(); i++) + if (s[i] != '\0') + t += s[i]; + else + t += '~'; + if (t.length() <= 64) + return t; + else + return t.substr(0, 30) + "..." + t.substr(s.length() - 31, 31); +} + +#define __testlib_readMany(readMany, readOne, typeName, space) \ + if (size < 0) \ + quit(_fail, #readMany ": size should be non-negative."); \ + if (size > 100000000) \ + quit(_fail, #readMany ": size should be at most 100000000."); \ + \ + std::vector result(size); \ + readManyIteration = indexBase; \ + \ + for (int i = 0; i < size; i++) \ + { \ + result[i] = readOne; \ + readManyIteration++; \ + if (strict && space && i + 1 < size) \ + readSpace(); \ + } \ + \ + readManyIteration = NO_INDEX; \ + return result; \ + + +std::string InStream::readWord(const pattern &p, const std::string &variableName) { + readWordTo(_tmpReadToken); + if (!p.matches(_tmpReadToken)) { + if (readManyIteration == NO_INDEX) { + if (variableName.empty()) + quit(_wa, + ("Token \"" + __testlib_part(_tmpReadToken) + "\" doesn't correspond to pattern \"" + p.src() + + "\"").c_str()); + else + quit(_wa, ("Token parameter [name=" + variableName + "] equals to \"" + __testlib_part(_tmpReadToken) + + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str()); + } else { + if (variableName.empty()) + quit(_wa, ("Token element [index=" + vtos(readManyIteration) + "] equals to \"" + + __testlib_part(_tmpReadToken) + "\" doesn't correspond to pattern \"" + p.src() + + "\"").c_str()); + else + quit(_wa, ("Token element " + variableName + "[" + vtos(readManyIteration) + "] equals to \"" + + __testlib_part(_tmpReadToken) + "\", doesn't correspond to pattern \"" + p.src() + + "\"").c_str()); + } + } + return _tmpReadToken; +} + +std::vector +InStream::readWords(int size, const pattern &p, const std::string &variablesName, int indexBase) { + __testlib_readMany(readWords, readWord(p, variablesName), std::string, true); +} + +std::vector InStream::readWords(int size, int indexBase) { + __testlib_readMany(readWords, readWord(), std::string, true); +} + +std::string InStream::readWord(const std::string &ptrn, const std::string &variableName) { + return readWord(pattern(ptrn), variableName); +} + +std::vector +InStream::readWords(int size, const std::string &ptrn, const std::string &variablesName, int indexBase) { + pattern p(ptrn); + __testlib_readMany(readWords, readWord(p, variablesName), std::string, true); +} + +std::string InStream::readToken(const pattern &p, const std::string &variableName) { + return readWord(p, variableName); +} + +std::vector +InStream::readTokens(int size, const pattern &p, const std::string &variablesName, int indexBase) { + __testlib_readMany(readTokens, readToken(p, variablesName), std::string, true); +} + +std::vector InStream::readTokens(int size, int indexBase) { + __testlib_readMany(readTokens, readToken(), std::string, true); +} + +std::string InStream::readToken(const std::string &ptrn, const std::string &variableName) { + return readWord(ptrn, variableName); +} + +std::vector +InStream::readTokens(int size, const std::string &ptrn, const std::string &variablesName, int indexBase) { + pattern p(ptrn); + __testlib_readMany(readTokens, readWord(p, variablesName), std::string, true); +} + +void InStream::readWordTo(std::string &result, const pattern &p, const std::string &variableName) { + readWordTo(result); + if (!p.matches(result)) { + if (variableName.empty()) + quit(_wa, ("Token \"" + __testlib_part(result) + "\" doesn't correspond to pattern \"" + p.src() + + "\"").c_str()); + else + quit(_wa, ("Token parameter [name=" + variableName + "] equals to \"" + __testlib_part(result) + + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str()); + } +} + +void InStream::readWordTo(std::string &result, const std::string &ptrn, const std::string &variableName) { + return readWordTo(result, pattern(ptrn), variableName); +} + +void InStream::readTokenTo(std::string &result, const pattern &p, const std::string &variableName) { + return readWordTo(result, p, variableName); +} + +void InStream::readTokenTo(std::string &result, const std::string &ptrn, const std::string &variableName) { + return readWordTo(result, ptrn, variableName); +} + +#ifdef __GNUC__ +__attribute__((pure)) +#endif +static inline bool equals(long long integer, const char *s) { + if (integer == LLONG_MIN) + return strcmp(s, "-9223372036854775808") == 0; + + if (integer == 0LL) + return strcmp(s, "0") == 0; + + size_t length = strlen(s); + + if (length == 0) + return false; + + if (integer < 0 && s[0] != '-') + return false; + + if (integer < 0) + s++, length--, integer = -integer; + + if (length == 0) + return false; + + while (integer > 0) { + int digit = int(integer % 10); + + if (s[length - 1] != '0' + digit) + return false; + + length--; + integer /= 10; + } + + return length == 0; +} + +#ifdef __GNUC__ +__attribute__((pure)) +#endif +static inline bool equals(unsigned long long integer, const char *s) { + if (integer == ULLONG_MAX) + return strcmp(s, "18446744073709551615") == 0; + + if (integer == 0ULL) + return strcmp(s, "0") == 0; + + size_t length = strlen(s); + + if (length == 0) + return false; + + while (integer > 0) { + int digit = int(integer % 10); + + if (s[length - 1] != '0' + digit) + return false; + + length--; + integer /= 10; + } + + return length == 0; +} + +static inline double stringToDouble(InStream &in, const char *buffer) { + double retval; + + size_t length = strlen(buffer); + + int minusCount = 0; + int plusCount = 0; + int decimalPointCount = 0; + int digitCount = 0; + int eCount = 0; + + for (size_t i = 0; i < length; i++) { + if (('0' <= buffer[i] && buffer[i] <= '9') || buffer[i] == '.' + || buffer[i] == 'e' || buffer[i] == 'E' + || buffer[i] == '-' || buffer[i] == '+') { + if ('0' <= buffer[i] && buffer[i] <= '9') + digitCount++; + if (buffer[i] == 'e' || buffer[i] == 'E') + eCount++; + if (buffer[i] == '-') + minusCount++; + if (buffer[i] == '+') + plusCount++; + if (buffer[i] == '.') + decimalPointCount++; + } else + in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + } + + // If for sure is not a number in standard notation or in e-notation. + if (digitCount == 0 || minusCount > 2 || plusCount > 2 || decimalPointCount > 1 || eCount > 1) + in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + char *suffix = new char[length + 1]; + std::memset(suffix, 0, length + 1); + int scanned = std::sscanf(buffer, "%lf%s", &retval, suffix); + bool empty = strlen(suffix) == 0; + delete[] suffix; + + if (scanned == 1 || (scanned == 2 && empty)) { + if (__testlib_isNaN(retval)) + in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + return retval; + } else + in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); +} + +static inline double stringToDouble(InStream &in, const std::string& buffer) { + for (size_t i = 0; i < buffer.length(); i++) + if (buffer[i] == '\0') + in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found (it contains \\0)").c_str()); + return stringToDouble(in, buffer.c_str()); +} + +static inline double stringToStrictDouble(InStream &in, const char *buffer, + int minAfterPointDigitCount, int maxAfterPointDigitCount) { + if (minAfterPointDigitCount < 0) + in.quit(_fail, "stringToStrictDouble: minAfterPointDigitCount should be non-negative."); + + if (minAfterPointDigitCount > maxAfterPointDigitCount) + in.quit(_fail, + "stringToStrictDouble: minAfterPointDigitCount should be less or equal to maxAfterPointDigitCount."); + + double retval; + + size_t length = strlen(buffer); + + if (length == 0 || length > 1000) + in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + if (buffer[0] != '-' && (buffer[0] < '0' || buffer[0] > '9')) + in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + int pointPos = -1; + for (size_t i = 1; i + 1 < length; i++) { + if (buffer[i] == '.') { + if (pointPos > -1) + in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + pointPos = int(i); + } + if (buffer[i] != '.' && (buffer[i] < '0' || buffer[i] > '9')) + in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + } + + if (buffer[length - 1] < '0' || buffer[length - 1] > '9') + in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + int afterDigitsCount = (pointPos == -1 ? 0 : int(length) - pointPos - 1); + if (afterDigitsCount < minAfterPointDigitCount || afterDigitsCount > maxAfterPointDigitCount) + in.quit(_pe, ("Expected strict double with number of digits after point in range [" + + vtos(minAfterPointDigitCount) + + "," + + vtos(maxAfterPointDigitCount) + + "], but \"" + __testlib_part(buffer) + "\" found").c_str() + ); + + int firstDigitPos = -1; + for (size_t i = 0; i < length; i++) + if (buffer[i] >= '0' && buffer[i] <= '9') { + firstDigitPos = int(i); + break; + } + + if (firstDigitPos > 1 || firstDigitPos == -1) + in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + if (buffer[firstDigitPos] == '0' && firstDigitPos + 1 < int(length) + && buffer[firstDigitPos + 1] >= '0' && buffer[firstDigitPos + 1] <= '9') + in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + char *suffix = new char[length + 1]; + std::memset(suffix, 0, length + 1); + int scanned = std::sscanf(buffer, "%lf%s", &retval, suffix); + bool empty = strlen(suffix) == 0; + delete[] suffix; + + if (scanned == 1 || (scanned == 2 && empty)) { + if (__testlib_isNaN(retval) || __testlib_isInfinite(retval)) + in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); + if (buffer[0] == '-' && retval >= 0) + in.quit(_pe, ("Redundant minus in \"" + __testlib_part(buffer) + "\" found").c_str()); + return retval; + } else + in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); +} + +static inline double stringToStrictDouble(InStream &in, const std::string& buffer, + int minAfterPointDigitCount, int maxAfterPointDigitCount) { + for (size_t i = 0; i < buffer.length(); i++) + if (buffer[i] == '\0') + in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found (it contains \\0)").c_str()); + return stringToStrictDouble(in, buffer.c_str(), minAfterPointDigitCount, maxAfterPointDigitCount); +} + +static inline long long stringToLongLong(InStream &in, const char *buffer) { + if (strcmp(buffer, "-9223372036854775808") == 0) + return LLONG_MIN; + + bool minus = false; + size_t length = strlen(buffer); + + if (length > 1 && buffer[0] == '-') + minus = true; + + if (length > 20) + in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + long long retval = 0LL; + + int zeroes = 0; + bool processingZeroes = true; + + for (int i = (minus ? 1 : 0); i < int(length); i++) { + if (buffer[i] == '0' && processingZeroes) + zeroes++; + else + processingZeroes = false; + + if (buffer[i] < '0' || buffer[i] > '9') + in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); + retval = retval * 10 + (buffer[i] - '0'); + } + + if (retval < 0) + in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + if ((zeroes > 0 && (retval != 0 || minus)) || zeroes > 1) + in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + retval = (minus ? -retval : +retval); + + if (length < 19) + return retval; + + if (equals(retval, buffer)) + return retval; + else + in.quit(_pe, ("Expected int64, but \"" + __testlib_part(buffer) + "\" found").c_str()); +} + +static inline long long stringToLongLong(InStream &in, const std::string& buffer) { + for (size_t i = 0; i < buffer.length(); i++) + if (buffer[i] == '\0') + in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found (it contains \\0)").c_str()); + return stringToLongLong(in, buffer.c_str()); +} + +static inline unsigned long long stringToUnsignedLongLong(InStream &in, const char *buffer) { + size_t length = strlen(buffer); + + if (length > 20) + in.quit(_pe, ("Expected unsigned integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); + if (length > 1 && buffer[0] == '0') + in.quit(_pe, ("Expected unsigned integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + unsigned long long retval = 0LL; + for (int i = 0; i < int(length); i++) { + if (buffer[i] < '0' || buffer[i] > '9') + in.quit(_pe, ("Expected unsigned integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); + retval = retval * 10 + (buffer[i] - '0'); + } + + if (length < 19) + return retval; + + if (length == 20 && strcmp(buffer, "18446744073709551615") > 0) + in.quit(_pe, ("Expected unsigned int64, but \"" + __testlib_part(buffer) + "\" found").c_str()); + + if (equals(retval, buffer)) + return retval; + else + in.quit(_pe, ("Expected unsigned int64, but \"" + __testlib_part(buffer) + "\" found").c_str()); +} + +static inline long long stringToUnsignedLongLong(InStream &in, const std::string& buffer) { + for (size_t i = 0; i < buffer.length(); i++) + if (buffer[i] == '\0') + in.quit(_pe, ("Expected unsigned integer, but \"" + __testlib_part(buffer) + "\" found (it contains \\0)").c_str()); + return stringToUnsignedLongLong(in, buffer.c_str()); +} + +int InStream::readInteger() { + if (!strict && seekEof()) + quit(_unexpected_eof, "Unexpected end of file - int32 expected"); + + readWordTo(_tmpReadToken); + + long long value = stringToLongLong(*this, _tmpReadToken); + if (value < INT_MIN || value > INT_MAX) + quit(_pe, ("Expected int32, but \"" + __testlib_part(_tmpReadToken) + "\" found").c_str()); + + return int(value); +} + +long long InStream::readLong() { + if (!strict && seekEof()) + quit(_unexpected_eof, "Unexpected end of file - int64 expected"); + + readWordTo(_tmpReadToken); + + return stringToLongLong(*this, _tmpReadToken); +} + +unsigned long long InStream::readUnsignedLong() { + if (!strict && seekEof()) + quit(_unexpected_eof, "Unexpected end of file - int64 expected"); + + readWordTo(_tmpReadToken); + + return stringToUnsignedLongLong(*this, _tmpReadToken); +} + +long long InStream::readLong(long long minv, long long maxv, const std::string &variableName) { + long long result = readLong(); + + if (result < minv || result > maxv) { + if (readManyIteration == NO_INDEX) { + if (variableName.empty()) + quit(_wa, ("Integer " + vtos(result) + " violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + + "]").c_str()); + else + quit(_wa, ("Integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + "]").c_str()); + } else { + if (variableName.empty()) + quit(_wa, ("Integer element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + "]").c_str()); + else + quit(_wa, + ("Integer element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to " + + vtos(result) + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + "]").c_str()); + } + } + + if (strict && !variableName.empty()) + validator.addBoundsHit(variableName, ValidatorBoundsHit(minv == result, maxv == result)); + + return result; +} + +std::vector +InStream::readLongs(int size, long long minv, long long maxv, const std::string &variablesName, int indexBase) { + __testlib_readMany(readLongs, readLong(minv, maxv, variablesName), long long, true) +} + +std::vector InStream::readLongs(int size, int indexBase) { + __testlib_readMany(readLongs, readLong(), long long, true) +} + +unsigned long long +InStream::readUnsignedLong(unsigned long long minv, unsigned long long maxv, const std::string &variableName) { + unsigned long long result = readUnsignedLong(); + + if (result < minv || result > maxv) { + if (readManyIteration == NO_INDEX) { + if (variableName.empty()) + quit(_wa, + ("Unsigned integer " + vtos(result) + " violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + + "]").c_str()); + else + quit(_wa, + ("Unsigned integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + "]").c_str()); + } else { + if (variableName.empty()) + quit(_wa, + ("Unsigned integer element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + "]").c_str()); + else + quit(_wa, ("Unsigned integer element " + std::string(variableName) + "[" + vtos(readManyIteration) + + "] equals to " + vtos(result) + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + + "]").c_str()); + } + } + + if (strict && !variableName.empty()) + validator.addBoundsHit(variableName, ValidatorBoundsHit(minv == result, maxv == result)); + + return result; +} + +std::vector InStream::readUnsignedLongs(int size, unsigned long long minv, unsigned long long maxv, + const std::string &variablesName, int indexBase) { + __testlib_readMany(readUnsignedLongs, readUnsignedLong(minv, maxv, variablesName), unsigned long long, true) +} + +std::vector InStream::readUnsignedLongs(int size, int indexBase) { + __testlib_readMany(readUnsignedLongs, readUnsignedLong(), unsigned long long, true) +} + +unsigned long long +InStream::readLong(unsigned long long minv, unsigned long long maxv, const std::string &variableName) { + return readUnsignedLong(minv, maxv, variableName); +} + +int InStream::readInt() { + return readInteger(); +} + +int InStream::readInt(int minv, int maxv, const std::string &variableName) { + int result = readInt(); + + if (result < minv || result > maxv) { + if (readManyIteration == NO_INDEX) { + if (variableName.empty()) + quit(_wa, ("Integer " + vtos(result) + " violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + + "]").c_str()); + else + quit(_wa, ("Integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + "]").c_str()); + } else { + if (variableName.empty()) + quit(_wa, ("Integer element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + "]").c_str()); + else + quit(_wa, + ("Integer element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to " + + vtos(result) + ", violates the range [" + toHumanReadableString(minv) + ", " + toHumanReadableString(maxv) + "]").c_str()); + } + } + + if (strict && !variableName.empty()) + validator.addBoundsHit(variableName, ValidatorBoundsHit(minv == result, maxv == result)); + + return result; +} + +int InStream::readInteger(int minv, int maxv, const std::string &variableName) { + return readInt(minv, maxv, variableName); +} + +std::vector InStream::readInts(int size, int minv, int maxv, const std::string &variablesName, int indexBase) { + __testlib_readMany(readInts, readInt(minv, maxv, variablesName), int, true) +} + +std::vector InStream::readInts(int size, int indexBase) { + __testlib_readMany(readInts, readInt(), int, true) +} + +std::vector InStream::readIntegers(int size, int minv, int maxv, const std::string &variablesName, int indexBase) { + __testlib_readMany(readIntegers, readInt(minv, maxv, variablesName), int, true) +} + +std::vector InStream::readIntegers(int size, int indexBase) { + __testlib_readMany(readIntegers, readInt(), int, true) +} + +double InStream::readReal() { + if (!strict && seekEof()) + quit(_unexpected_eof, "Unexpected end of file - double expected"); + + return stringToDouble(*this, readWord()); +} + +double InStream::readDouble() { + return readReal(); +} + +double InStream::readReal(double minv, double maxv, const std::string &variableName) { + double result = readReal(); + + if (result < minv || result > maxv) { + if (readManyIteration == NO_INDEX) { + if (variableName.empty()) + quit(_wa, ("Double " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + + "]").c_str()); + else + quit(_wa, ("Double parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); + } else { + if (variableName.empty()) + quit(_wa, ("Double element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); + else + quit(_wa, + ("Double element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to " + + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); + } + } + + if (strict && !variableName.empty()) + validator.addBoundsHit(variableName, ValidatorBoundsHit( + doubleDelta(minv, result) < ValidatorBoundsHit::EPS, + doubleDelta(maxv, result) < ValidatorBoundsHit::EPS + )); + + return result; +} + +std::vector +InStream::readReals(int size, double minv, double maxv, const std::string &variablesName, int indexBase) { + __testlib_readMany(readReals, readReal(minv, maxv, variablesName), double, true) +} + +std::vector InStream::readReals(int size, int indexBase) { + __testlib_readMany(readReals, readReal(), double, true) +} + +double InStream::readDouble(double minv, double maxv, const std::string &variableName) { + return readReal(minv, maxv, variableName); +} + +std::vector +InStream::readDoubles(int size, double minv, double maxv, const std::string &variablesName, int indexBase) { + __testlib_readMany(readDoubles, readDouble(minv, maxv, variablesName), double, true) +} + +std::vector InStream::readDoubles(int size, int indexBase) { + __testlib_readMany(readDoubles, readDouble(), double, true) +} + +double InStream::readStrictReal(double minv, double maxv, + int minAfterPointDigitCount, int maxAfterPointDigitCount, + const std::string &variableName) { + if (!strict && seekEof()) + quit(_unexpected_eof, "Unexpected end of file - strict double expected"); + + double result = stringToStrictDouble(*this, readWord(), minAfterPointDigitCount, maxAfterPointDigitCount); + + if (result < minv || result > maxv) { + if (readManyIteration == NO_INDEX) { + if (variableName.empty()) + quit(_wa, ("Strict double " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + + "]").c_str()); + else + quit(_wa, + ("Strict double parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); + } else { + if (variableName.empty()) + quit(_wa, ("Strict double element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); + else + quit(_wa, ("Strict double element " + std::string(variableName) + "[" + vtos(readManyIteration) + + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + + "]").c_str()); + } + } + + if (strict && !variableName.empty()) + validator.addBoundsHit(variableName, ValidatorBoundsHit( + doubleDelta(minv, result) < ValidatorBoundsHit::EPS, + doubleDelta(maxv, result) < ValidatorBoundsHit::EPS + )); + + return result; +} + +std::vector InStream::readStrictReals(int size, double minv, double maxv, + int minAfterPointDigitCount, int maxAfterPointDigitCount, + const std::string &variablesName, int indexBase) { + __testlib_readMany(readStrictReals, + readStrictReal(minv, maxv, minAfterPointDigitCount, maxAfterPointDigitCount, variablesName), + double, true) +} + +double InStream::readStrictDouble(double minv, double maxv, + int minAfterPointDigitCount, int maxAfterPointDigitCount, + const std::string &variableName) { + return readStrictReal(minv, maxv, + minAfterPointDigitCount, maxAfterPointDigitCount, + variableName); +} + +std::vector InStream::readStrictDoubles(int size, double minv, double maxv, + int minAfterPointDigitCount, int maxAfterPointDigitCount, + const std::string &variablesName, int indexBase) { + __testlib_readMany(readStrictDoubles, + readStrictDouble(minv, maxv, minAfterPointDigitCount, maxAfterPointDigitCount, variablesName), + double, true) +} + +bool InStream::eof() { + if (!strict && NULL == reader) + return true; + + return reader->eof(); +} + +bool InStream::seekEof() { + if (!strict && NULL == reader) + return true; + skipBlanks(); + return eof(); +} + +bool InStream::eoln() { + if (!strict && NULL == reader) + return true; + + int c = reader->nextChar(); + + if (!strict) { + if (c == EOFC) + return true; + + if (c == CR) { + c = reader->nextChar(); + + if (c != LF) { + reader->unreadChar(c); + reader->unreadChar(CR); + return false; + } else + return true; + } + + if (c == LF) + return true; + + reader->unreadChar(c); + return false; + } else { + bool returnCr = false; + +#if (defined(ON_WINDOWS) && !defined(FOR_LINUX)) || defined(FOR_WINDOWS) + if (c != CR) { + reader->unreadChar(c); + return false; + } else { + if (!returnCr) + returnCr = true; + c = reader->nextChar(); + } +#endif + if (c != LF) { + reader->unreadChar(c); + if (returnCr) + reader->unreadChar(CR); + return false; + } + + return true; + } +} + +void InStream::readEoln() { + lastLine = reader->getLine(); + if (!eoln()) + quit(_pe, "Expected EOLN"); +} + +void InStream::readEof() { + lastLine = reader->getLine(); + if (!eof()) + quit(_pe, "Expected EOF"); + + if (TestlibFinalizeGuard::alive && this == &inf) + testlibFinalizeGuard.readEofCount++; +} + +bool InStream::seekEoln() { + if (!strict && NULL == reader) + return true; + + int cur; + do { + cur = reader->nextChar(); + } while (cur == SPACE || cur == TAB); + + reader->unreadChar(cur); + return eoln(); +} + +void InStream::nextLine() { + readLine(); +} + +void InStream::readStringTo(std::string &result) { + if (NULL == reader) + quit(_pe, "Expected line"); + + result.clear(); + + for (;;) { + int cur = reader->curChar(); + + if (cur == LF || cur == EOFC) + break; + + if (cur == CR) { + cur = reader->nextChar(); + if (reader->curChar() == LF) { + reader->unreadChar(cur); + break; + } + } + + lastLine = reader->getLine(); + result += char(reader->nextChar()); + } + + if (strict) + readEoln(); + else + eoln(); +} + +std::string InStream::readString() { + readStringTo(_tmpReadToken); + return _tmpReadToken; +} + +std::vector InStream::readStrings(int size, int indexBase) { + __testlib_readMany(readStrings, readString(), std::string, false) +} + +void InStream::readStringTo(std::string &result, const pattern &p, const std::string &variableName) { + readStringTo(result); + if (!p.matches(result)) { + if (readManyIteration == NO_INDEX) { + if (variableName.empty()) + quit(_wa, ("Line \"" + __testlib_part(result) + "\" doesn't correspond to pattern \"" + p.src() + + "\"").c_str()); + else + quit(_wa, ("Line [name=" + variableName + "] equals to \"" + __testlib_part(result) + + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str()); + } else { + if (variableName.empty()) + quit(_wa, + ("Line element [index=" + vtos(readManyIteration) + "] equals to \"" + __testlib_part(result) + + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str()); + else + quit(_wa, + ("Line element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to \"" + + __testlib_part(result) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str()); + } + } +} + +void InStream::readStringTo(std::string &result, const std::string &ptrn, const std::string &variableName) { + readStringTo(result, pattern(ptrn), variableName); +} + +std::string InStream::readString(const pattern &p, const std::string &variableName) { + readStringTo(_tmpReadToken, p, variableName); + return _tmpReadToken; +} + +std::vector +InStream::readStrings(int size, const pattern &p, const std::string &variablesName, int indexBase) { + __testlib_readMany(readStrings, readString(p, variablesName), std::string, false) +} + +std::string InStream::readString(const std::string &ptrn, const std::string &variableName) { + readStringTo(_tmpReadToken, ptrn, variableName); + return _tmpReadToken; +} + +std::vector +InStream::readStrings(int size, const std::string &ptrn, const std::string &variablesName, int indexBase) { + pattern p(ptrn); + __testlib_readMany(readStrings, readString(p, variablesName), std::string, false) +} + +void InStream::readLineTo(std::string &result) { + readStringTo(result); +} + +std::string InStream::readLine() { + return readString(); +} + +std::vector InStream::readLines(int size, int indexBase) { + __testlib_readMany(readLines, readString(), std::string, false) +} + +void InStream::readLineTo(std::string &result, const pattern &p, const std::string &variableName) { + readStringTo(result, p, variableName); +} + +void InStream::readLineTo(std::string &result, const std::string &ptrn, const std::string &variableName) { + readStringTo(result, ptrn, variableName); +} + +std::string InStream::readLine(const pattern &p, const std::string &variableName) { + return readString(p, variableName); +} + +std::vector +InStream::readLines(int size, const pattern &p, const std::string &variablesName, int indexBase) { + __testlib_readMany(readLines, readString(p, variablesName), std::string, false) +} + +std::string InStream::readLine(const std::string &ptrn, const std::string &variableName) { + return readString(ptrn, variableName); +} + +std::vector +InStream::readLines(int size, const std::string &ptrn, const std::string &variablesName, int indexBase) { + pattern p(ptrn); + __testlib_readMany(readLines, readString(p, variablesName), std::string, false) +} + +#ifdef __GNUC__ +__attribute__ ((format (printf, 3, 4))) +#endif +void InStream::ensuref(bool cond, const char *format, ...) { + if (!cond) { + FMT_TO_RESULT(format, format, message); + this->__testlib_ensure(cond, message); + } +} + +void InStream::__testlib_ensure(bool cond, std::string message) { + if (!cond) + this->quit(_wa, message.c_str()); +} + +void InStream::close() { + if (NULL != reader) { + reader->close(); + delete reader; + reader = NULL; + } + + opened = false; +} + +NORETURN void quit(TResult result, const std::string &msg) { + ouf.quit(result, msg.c_str()); +} + +NORETURN void quit(TResult result, const char *msg) { + ouf.quit(result, msg); +} + +NORETURN void __testlib_quitp(double points, const char *message) { + __testlib_points = points; + std::string stringPoints = removeDoubleTrailingZeroes(format("%.10f", points)); + + std::string quitMessage; + if (NULL == message || 0 == strlen(message)) + quitMessage = stringPoints; + else + quitMessage = stringPoints + " " + message; + + quit(_points, quitMessage.c_str()); +} + +NORETURN void __testlib_quitp(int points, const char *message) { + __testlib_points = points; + std::string stringPoints = format("%d", points); + + std::string quitMessage; + if (NULL == message || 0 == strlen(message)) + quitMessage = stringPoints; + else + quitMessage = stringPoints + " " + message; + + quit(_points, quitMessage.c_str()); +} + +NORETURN void quitp(float points, const std::string &message = "") { + __testlib_quitp(double(points), message.c_str()); +} + +NORETURN void quitp(double points, const std::string &message = "") { + __testlib_quitp(points, message.c_str()); +} + +NORETURN void quitp(long double points, const std::string &message = "") { + __testlib_quitp(double(points), message.c_str()); +} + +NORETURN void quitp(int points, const std::string &message = "") { + __testlib_quitp(points, message.c_str()); +} + +NORETURN void quitpi(const std::string &points_info, const std::string &message = "") { + if (points_info.find(' ') != std::string::npos) + quit(_fail, "Parameter 'points_info' can't contain spaces"); + if (message.empty()) + quit(_points, ("points_info=" + points_info).c_str()); + else + quit(_points, ("points_info=" + points_info + " " + message).c_str()); +} + +template +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +NORETURN void quitp(F points, const char *format, ...) { + FMT_TO_RESULT(format, format, message); + quitp(points, message); +} + +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +NORETURN void quitf(TResult result, const char *format, ...) { + FMT_TO_RESULT(format, format, message); + quit(result, message); +} + +#ifdef __GNUC__ +__attribute__ ((format (printf, 3, 4))) +#endif +void quitif(bool condition, TResult result, const char *format, ...) { + if (condition) { + FMT_TO_RESULT(format, format, message); + quit(result, message); + } +} + +NORETURN void __testlib_help() { + InStream::textColor(InStream::LightCyan); + std::fprintf(stderr, "TESTLIB %s, https://github.com/MikeMirzayanov/testlib/ ", VERSION); + std::fprintf(stderr, "by Mike Mirzayanov, copyright(c) 2005-2020\n"); + std::fprintf(stderr, "Checker name: \"%s\"\n", checkerName.c_str()); + InStream::textColor(InStream::LightGray); + + std::fprintf(stderr, "\n"); + std::fprintf(stderr, "Latest features: \n"); + for (size_t i = 0; i < sizeof(latestFeatures) / sizeof(char *); i++) { + std::fprintf(stderr, "*) %s\n", latestFeatures[i]); + } + std::fprintf(stderr, "\n"); + + std::fprintf(stderr, "Program must be run with the following arguments: \n"); + std::fprintf(stderr, " [--testset testset] [--group group] [ [<-appes>]]\n\n"); + + __testlib_exitCode = FAIL_EXIT_CODE; + std::exit(FAIL_EXIT_CODE); +} + +static void __testlib_ensuresPreconditions() { + // testlib assumes: sizeof(int) = 4. + __TESTLIB_STATIC_ASSERT(sizeof(int) == 4); + + // testlib assumes: INT_MAX == 2147483647. + __TESTLIB_STATIC_ASSERT(INT_MAX == 2147483647); + + // testlib assumes: sizeof(long long) = 8. + __TESTLIB_STATIC_ASSERT(sizeof(long long) == 8); + + // testlib assumes: sizeof(double) = 8. + __TESTLIB_STATIC_ASSERT(sizeof(double) == 8); + + // testlib assumes: no -ffast-math. + if (!__testlib_isNaN(+__testlib_nan())) + quit(_fail, "Function __testlib_isNaN is not working correctly: possible reason is '-ffast-math'"); + if (!__testlib_isNaN(-__testlib_nan())) + quit(_fail, "Function __testlib_isNaN is not working correctly: possible reason is '-ffast-math'"); +} + +std::string __testlib_testset; + +std::string getTestset() { + return __testlib_testset; +} + +std::string __testlib_group; + +std::string getGroup() { + return __testlib_group; +} + +static void __testlib_set_testset_and_group(int argc, char* argv[]) { + for (int i = 1; i < argc; i++) { + if (!strcmp("--testset", argv[i])) { + if (i + 1 < argc && strlen(argv[i + 1]) > 0) + __testlib_testset = argv[++i]; + else + quit(_fail, std::string("Expected non-empty testset after --testset command line parameter")); + } else if (!strcmp("--group", argv[i])) { + if (i + 1 < argc) + __testlib_group = argv[++i]; + else + quit(_fail, std::string("Expected group after --group command line parameter")); + } + } +} + +void registerGen(int argc, char *argv[], int randomGeneratorVersion) { + if (randomGeneratorVersion < 0 || randomGeneratorVersion > 1) + quitf(_fail, "Random generator version is expected to be 0 or 1."); + random_t::version = randomGeneratorVersion; + + __testlib_ensuresPreconditions(); + TestlibFinalizeGuard::registered = true; + + testlibMode = _generator; + __testlib_set_binary(stdin); + rnd.setSeed(argc, argv); + +#if __cplusplus > 199711L || defined(_MSC_VER) + prepareOpts(argc, argv); +#endif +} + +#ifdef USE_RND_AS_BEFORE_087 +void registerGen(int argc, char* argv[]) +{ + registerGen(argc, argv, 0); +} +#else +#ifdef __GNUC__ +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 4)) +__attribute__ ((deprecated("Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)." +" The third parameter stands for the random generator version." +" If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)." +" Version 1 has been released on Spring, 2013. Use it to write new generators."))) +#else +__attribute__ ((deprecated)) +#endif +#endif +#ifdef _MSC_VER +__declspec(deprecated("Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)." + " The third parameter stands for the random generator version." + " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)." + " Version 1 has been released on Spring, 2013. Use it to write new generators.")) +#endif +void registerGen(int argc, char *argv[]) { + std::fprintf(stderr, "Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)." + " The third parameter stands for the random generator version." + " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)." + " Version 1 has been released on Spring, 2013. Use it to write new generators.\n\n"); + registerGen(argc, argv, 0); +} +#endif + +void registerInteraction(int argc, char *argv[]) { + __testlib_ensuresPreconditions(); + __testlib_set_testset_and_group(argc, argv); + TestlibFinalizeGuard::registered = true; + + testlibMode = _interactor; + __testlib_set_binary(stdin); + + if (argc > 1 && !strcmp("--help", argv[1])) + __testlib_help(); + + if (argc < 3 || argc > 6) { + quit(_fail, std::string("Program must be run with the following arguments: ") + + std::string(" [ [ [<-appes>]]]") + + "\nUse \"--help\" to get help information"); + } + + if (argc <= 4) { + resultName = ""; + appesMode = false; + } + +#ifndef EJUDGE + if (argc == 5) { + resultName = argv[4]; + appesMode = false; + } + + if (argc == 6) { + if (strcmp("-APPES", argv[5]) && strcmp("-appes", argv[5])) { + quit(_fail, std::string("Program must be run with the following arguments: ") + + " [ [<-appes>]]"); + } else { + resultName = argv[4]; + appesMode = true; + } + } +#endif + + inf.init(argv[1], _input); + + tout.open(argv[2], std::ios_base::out); + if (tout.fail() || !tout.is_open()) + quit(_fail, std::string("Can not write to the test-output-file '") + argv[2] + std::string("'")); + + ouf.init(stdin, _output); + + if (argc >= 4) + ans.init(argv[3], _answer); + else + ans.name = "unopened answer stream"; +} + +void registerValidation() { + __testlib_ensuresPreconditions(); + TestlibFinalizeGuard::registered = true; + + testlibMode = _validator; + + __testlib_set_binary(stdin); + __testlib_set_binary(stdout); + __testlib_set_binary(stderr); + + inf.init(stdin, _input); + inf.strict = true; +} + +void registerValidation(int argc, char *argv[]) { + registerValidation(); + __testlib_set_testset_and_group(argc, argv); + + validator.initialize(); + TestlibFinalizeGuard::registered = true; + + std::string comment = "Validator must be run with the following arguments:" + " [--testset testset]" + " [--group group]" + " [--testOverviewLogFileName fileName]" + " [--testMarkupFileName fileName]" + " [--testCase testCase]" + " [--testCaseFileName fileName]" + ; + + for (int i = 1; i < argc; i++) { + if (!strcmp("--testset", argv[i])) { + if (i + 1 < argc && strlen(argv[i + 1]) > 0) + validator.setTestset(argv[++i]); + else + quit(_fail, comment); + } + if (!strcmp("--group", argv[i])) { + if (i + 1 < argc) + validator.setGroup(argv[++i]); + else + quit(_fail, comment); + } + if (!strcmp("--testOverviewLogFileName", argv[i])) { + if (i + 1 < argc) + validator.setTestOverviewLogFileName(argv[++i]); + else + quit(_fail, comment); + } + if (!strcmp("--testMarkupFileName", argv[i])) { + if (i + 1 < argc) + validator.setTestMarkupFileName(argv[++i]); + else + quit(_fail, comment); + } + if (!strcmp("--testCase", argv[i])) { + if (i + 1 < argc) { + long long testCase = stringToLongLong(inf, argv[++i]); + if (testCase < 1 || testCase >= __TESTLIB_MAX_TEST_CASE) + quit(_fail, format("Argument testCase should be between 1 and %d, but ", __TESTLIB_MAX_TEST_CASE) + + toString(testCase) + " found"); + validator.setTestCase(int(testCase)); + } else + quit(_fail, comment); + } + if (!strcmp("--testCaseFileName", argv[i])) { + if (i + 1 < argc) { + validator.setTestCaseFileName(argv[++i]); + } else + quit(_fail, comment); + } + } +} + +void addFeature(const std::string &feature) { + if (testlibMode != _validator) + quit(_fail, "Features are supported in validators only."); + validator.addFeature(feature); +} + +void feature(const std::string &feature) { + if (testlibMode != _validator) + quit(_fail, "Features are supported in validators only."); + validator.feature(feature); +} + +class Checker { +private: + bool _initialized; + std::string _testset; + std::string _group; + +public: + Checker() : _initialized(false), _testset("tests"), _group() { + } + + void initialize() { + _initialized = true; + } + + std::string testset() const { + if (!_initialized) + __testlib_fail("Checker should be initialized with registerTestlibCmd(argc, argv) instead of registerTestlibCmd() to support checker.testset()"); + return _testset; + } + + std::string group() const { + if (!_initialized) + __testlib_fail("Checker should be initialized with registerTestlibCmd(argc, argv) instead of registerTestlibCmd() to support checker.group()"); + return _group; + } + + void setTestset(const char *const testset) { + _testset = testset; + } + + void setGroup(const char *const group) { + _group = group; + } +} checker; + +void registerTestlibCmd(int argc, char *argv[]) { + __testlib_ensuresPreconditions(); + __testlib_set_testset_and_group(argc, argv); + TestlibFinalizeGuard::registered = true; + + testlibMode = _checker; + __testlib_set_binary(stdin); + + std::vector args(1, argv[0]); + checker.initialize(); + + for (int i = 1; i < argc; i++) { + if (!strcmp("--testset", argv[i])) { + if (i + 1 < argc && strlen(argv[i + 1]) > 0) + checker.setTestset(argv[++i]); + else + quit(_fail, std::string("Expected testset after --testset command line parameter")); + } else if (!strcmp("--group", argv[i])) { + if (i + 1 < argc) + checker.setGroup(argv[++i]); + else + quit(_fail, std::string("Expected group after --group command line parameter")); + } else + args.push_back(argv[i]); + } + + argc = int(args.size()); + if (argc > 1 && "--help" == args[1]) + __testlib_help(); + + if (argc < 4 || argc > 6) { + quit(_fail, std::string("Program must be run with the following arguments: ") + + std::string("[--testset testset] [--group group] [ [<-appes>]]") + + "\nUse \"--help\" to get help information"); + } + + if (argc == 4) { + resultName = ""; + appesMode = false; + } + + if (argc == 5) { + resultName = args[4]; + appesMode = false; + } + + if (argc == 6) { + if ("-APPES" != args[5] && "-appes" != args[5]) { + quit(_fail, std::string("Program must be run with the following arguments: ") + + " [ [<-appes>]]"); + } else { + resultName = args[4]; + appesMode = true; + } + } + + #ifdef BOCA_SUPPORT + inf.init(argv[3], _input); + ouf.init(argv[1], _output); + ans.init(argv[2], _answer); + #else + inf.init(argv[1], _input); + ouf.init(argv[2], _output); + ans.init(argv[3], _answer); + #endif +} + +void registerTestlib(int argc, ...) { + if (argc < 3 || argc > 5) + quit(_fail, std::string("Program must be run with the following arguments: ") + + " [ [<-appes>]]"); + + char **argv = new char *[argc + 1]; + + va_list ap; + va_start(ap, argc); + argv[0] = NULL; + for (int i = 0; i < argc; i++) { + argv[i + 1] = va_arg(ap, char*); + } + va_end(ap); + + registerTestlibCmd(argc + 1, argv); + delete[] argv; +} + +static inline void __testlib_ensure(bool cond, const std::string &msg) { + if (!cond) + quit(_fail, msg.c_str()); +} + +#ifdef __GNUC__ +__attribute__((unused)) +#endif +static inline void __testlib_ensure(bool cond, const char *msg) { + if (!cond) + quit(_fail, msg); +} + +#define ensure(cond) __testlib_ensure(cond, "Condition failed: \"" #cond "\"") +#define STRINGIZE_DETAIL(x) #x +#define STRINGIZE(x) STRINGIZE_DETAIL(x) +#define ensure_ext(cond) __testlib_ensure(cond, "Line " STRINGIZE(__LINE__) ": Condition failed: \"" #cond "\"") + +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +inline void ensuref(bool cond, const char *format, ...) { + if (!cond) { + FMT_TO_RESULT(format, format, message); + __testlib_ensure(cond, message); + } +} + +NORETURN static void __testlib_fail(const std::string &message) { + quitf(_fail, "%s", message.c_str()); +} + +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +void setName(const char *format, ...) { + FMT_TO_RESULT(format, format, name); + checkerName = name; +} + +/* + * Do not use random_shuffle, because it will produce different result + * for different C++ compilers. + * + * This implementation uses testlib random_t to produce random numbers, so + * it is stable. + */ +template +void shuffle(_RandomAccessIter __first, _RandomAccessIter __last) { + if (__first == __last) return; + for (_RandomAccessIter __i = __first + 1; __i != __last; ++__i) + std::iter_swap(__i, __first + rnd.next(int(__i - __first) + 1)); +} + + +template +#if defined(__GNUC__) && !defined(__clang__) +__attribute__ ((error("Don't use random_shuffle(), use shuffle() instead"))) +#endif +void random_shuffle(_RandomAccessIter, _RandomAccessIter) { + quitf(_fail, "Don't use random_shuffle(), use shuffle() instead"); +} + +#ifdef __GLIBC__ +# define RAND_THROW_STATEMENT throw() +#else +# define RAND_THROW_STATEMENT +#endif + +#if defined(__GNUC__) && !defined(__clang__) + +__attribute__ ((error("Don't use rand(), use rnd.next() instead"))) +#endif +#ifdef _MSC_VER +# pragma warning( disable : 4273 ) +#endif +int rand() RAND_THROW_STATEMENT +{ + quitf(_fail, "Don't use rand(), use rnd.next() instead"); + + /* This line never runs. */ + //throw "Don't use rand(), use rnd.next() instead"; +} + +#if defined(__GNUC__) && !defined(__clang__) + +__attribute__ ((error("Don't use srand(), you should use " +"'registerGen(argc, argv, 1);' to initialize generator seed " +"by hash code of the command line params. The third parameter " +"is randomGeneratorVersion (currently the latest is 1)."))) +#endif +#ifdef _MSC_VER +# pragma warning( disable : 4273 ) +#endif +void srand(unsigned int seed) RAND_THROW_STATEMENT +{ + quitf(_fail, "Don't use srand(), you should use " + "'registerGen(argc, argv, 1);' to initialize generator seed " + "by hash code of the command line params. The third parameter " + "is randomGeneratorVersion (currently the latest is 1) [ignored seed=%u].", seed); +} + +void startTest(int test) { + const std::string testFileName = vtos(test); + if (NULL == freopen(testFileName.c_str(), "wt", stdout)) + __testlib_fail("Unable to write file '" + testFileName + "'"); +} + +inline std::string upperCase(std::string s) { + for (size_t i = 0; i < s.length(); i++) + if ('a' <= s[i] && s[i] <= 'z') + s[i] = char(s[i] - 'a' + 'A'); + return s; +} + +inline std::string lowerCase(std::string s) { + for (size_t i = 0; i < s.length(); i++) + if ('A' <= s[i] && s[i] <= 'Z') + s[i] = char(s[i] - 'A' + 'a'); + return s; +} + +inline std::string compress(const std::string &s) { + return __testlib_part(s); +} + +inline std::string englishEnding(int x) { + x %= 100; + if (x / 10 == 1) + return "th"; + if (x % 10 == 1) + return "st"; + if (x % 10 == 2) + return "nd"; + if (x % 10 == 3) + return "rd"; + return "th"; +} + +template +std::string join(_ForwardIterator first, _ForwardIterator last, _Separator separator) { + std::stringstream ss; + bool repeated = false; + for (_ForwardIterator i = first; i != last; i++) { + if (repeated) + ss << separator; + else + repeated = true; + ss << *i; + } + return ss.str(); +} + +template +std::string join(_ForwardIterator first, _ForwardIterator last) { + return join(first, last, ' '); +} + +template +std::string join(const _Collection &collection, _Separator separator) { + return join(collection.begin(), collection.end(), separator); +} + +template +std::string join(const _Collection &collection) { + return join(collection, ' '); +} + +/** + * Splits string s by character separator returning exactly k+1 items, + * where k is the number of separator occurences. + */ +std::vector split(const std::string &s, char separator) { + std::vector result; + std::string item; + for (size_t i = 0; i < s.length(); i++) + if (s[i] == separator) { + result.push_back(item); + item = ""; + } else + item += s[i]; + result.push_back(item); + return result; +} + +/** + * Splits string s by character separators returning exactly k+1 items, + * where k is the number of separator occurences. + */ +std::vector split(const std::string &s, const std::string &separators) { + if (separators.empty()) + return std::vector(1, s); + + std::vector isSeparator(256); + for (size_t i = 0; i < separators.size(); i++) + isSeparator[(unsigned char) (separators[i])] = true; + + std::vector result; + std::string item; + for (size_t i = 0; i < s.length(); i++) + if (isSeparator[(unsigned char) (s[i])]) { + result.push_back(item); + item = ""; + } else + item += s[i]; + result.push_back(item); + return result; +} + +/** + * Splits string s by character separator returning non-empty items. + */ +std::vector tokenize(const std::string &s, char separator) { + std::vector result; + std::string item; + for (size_t i = 0; i < s.length(); i++) + if (s[i] == separator) { + if (!item.empty()) + result.push_back(item); + item = ""; + } else + item += s[i]; + if (!item.empty()) + result.push_back(item); + return result; +} + +/** + * Splits string s by character separators returning non-empty items. + */ +std::vector tokenize(const std::string &s, const std::string &separators) { + if (separators.empty()) + return std::vector(1, s); + + std::vector isSeparator(256); + for (size_t i = 0; i < separators.size(); i++) + isSeparator[(unsigned char) (separators[i])] = true; + + std::vector result; + std::string item; + for (size_t i = 0; i < s.length(); i++) + if (isSeparator[(unsigned char) (s[i])]) { + if (!item.empty()) + result.push_back(item); + item = ""; + } else + item += s[i]; + + if (!item.empty()) + result.push_back(item); + + return result; +} + +NORETURN void __testlib_expectedButFound(TResult result, std::string expected, std::string found, const char *prepend) { + std::string message; + if (strlen(prepend) != 0) + message = format("%s: expected '%s', but found '%s'", + compress(prepend).c_str(), compress(expected).c_str(), compress(found).c_str()); + else + message = format("expected '%s', but found '%s'", + compress(expected).c_str(), compress(found).c_str()); + quit(result, message); +} + +NORETURN void __testlib_expectedButFound(TResult result, double expected, double found, const char *prepend) { + std::string expectedString = removeDoubleTrailingZeroes(format("%.12f", expected)); + std::string foundString = removeDoubleTrailingZeroes(format("%.12f", found)); + __testlib_expectedButFound(result, expectedString, foundString, prepend); +} + +template +#ifdef __GNUC__ +__attribute__ ((format (printf, 4, 5))) +#endif +NORETURN void expectedButFound(TResult result, T expected, T found, const char *prependFormat = "", ...) { + FMT_TO_RESULT(prependFormat, prependFormat, prepend); + std::string expectedString = vtos(expected); + std::string foundString = vtos(found); + __testlib_expectedButFound(result, expectedString, foundString, prepend.c_str()); +} + +template<> +#ifdef __GNUC__ +__attribute__ ((format (printf, 4, 5))) +#endif +NORETURN void +expectedButFound(TResult result, std::string expected, std::string found, const char *prependFormat, ...) { + FMT_TO_RESULT(prependFormat, prependFormat, prepend); + __testlib_expectedButFound(result, expected, found, prepend.c_str()); +} + +template<> +#ifdef __GNUC__ +__attribute__ ((format (printf, 4, 5))) +#endif +NORETURN void expectedButFound(TResult result, double expected, double found, const char *prependFormat, ...) { + FMT_TO_RESULT(prependFormat, prependFormat, prepend); + std::string expectedString = removeDoubleTrailingZeroes(format("%.12f", expected)); + std::string foundString = removeDoubleTrailingZeroes(format("%.12f", found)); + __testlib_expectedButFound(result, expectedString, foundString, prepend.c_str()); +} + +template<> +#ifdef __GNUC__ +__attribute__ ((format (printf, 4, 5))) +#endif +NORETURN void +expectedButFound(TResult result, const char *expected, const char *found, const char *prependFormat, + ...) { + FMT_TO_RESULT(prependFormat, prependFormat, prepend); + __testlib_expectedButFound(result, std::string(expected), std::string(found), prepend.c_str()); +} + +template<> +#ifdef __GNUC__ +__attribute__ ((format (printf, 4, 5))) +#endif +NORETURN void expectedButFound(TResult result, float expected, float found, const char *prependFormat, ...) { + FMT_TO_RESULT(prependFormat, prependFormat, prepend); + __testlib_expectedButFound(result, double(expected), double(found), prepend.c_str()); +} + +template<> +#ifdef __GNUC__ +__attribute__ ((format (printf, 4, 5))) +#endif +NORETURN void +expectedButFound(TResult result, long double expected, long double found, const char *prependFormat, ...) { + FMT_TO_RESULT(prependFormat, prependFormat, prepend); + __testlib_expectedButFound(result, double(expected), double(found), prepend.c_str()); +} + +#if __cplusplus > 199711L || defined(_MSC_VER) +template +struct is_iterable { + template + static char test(typename U::iterator *x); + + template + static long test(U *x); + + static const bool value = sizeof(test(0)) == 1; +}; + +template +struct __testlib_enable_if { +}; + +template +struct __testlib_enable_if { + typedef T type; +}; + +template +typename __testlib_enable_if::value, void>::type __testlib_print_one(const T &t) { + std::cout << t; +} + +template +typename __testlib_enable_if::value, void>::type __testlib_print_one(const T &t) { + bool first = true; + for (typename T::const_iterator i = t.begin(); i != t.end(); i++) { + if (first) + first = false; + else + std::cout << " "; + std::cout << *i; + } +} + +template<> +typename __testlib_enable_if::value, void>::type +__testlib_print_one(const std::string &t) { + std::cout << t; +} + +template +void __println_range(A begin, B end) { + bool first = true; + for (B i = B(begin); i != end; i++) { + if (first) + first = false; + else + std::cout << " "; + __testlib_print_one(*i); + } + std::cout << std::endl; +} + +template +struct is_iterator { + static T makeT(); + + typedef void *twoptrs[2]; + + static twoptrs &test(...); + + template + static typename R::iterator_category *test(R); + + template + static void *test(R *); + + static const bool value = sizeof(test(makeT())) == sizeof(void *); +}; + +template +struct is_iterator::value>::type> { + static const bool value = false; +}; + +template +typename __testlib_enable_if::value, void>::type println(const A &a, const B &b) { + __testlib_print_one(a); + std::cout << " "; + __testlib_print_one(b); + std::cout << std::endl; +} + +template +typename __testlib_enable_if::value, void>::type println(const A &a, const B &b) { + __println_range(a, b); +} + +template +void println(const A *a, const A *b) { + __println_range(a, b); +} + +template<> +void println(const char *a, const char *b) { + __testlib_print_one(a); + std::cout << " "; + __testlib_print_one(b); + std::cout << std::endl; +} + +template +void println(const T &x) { + __testlib_print_one(x); + std::cout << std::endl; +} + +template +void println(const A &a, const B &b, const C &c) { + __testlib_print_one(a); + std::cout << " "; + __testlib_print_one(b); + std::cout << " "; + __testlib_print_one(c); + std::cout << std::endl; +} + +template +void println(const A &a, const B &b, const C &c, const D &d) { + __testlib_print_one(a); + std::cout << " "; + __testlib_print_one(b); + std::cout << " "; + __testlib_print_one(c); + std::cout << " "; + __testlib_print_one(d); + std::cout << std::endl; +} + +template +void println(const A &a, const B &b, const C &c, const D &d, const E &e) { + __testlib_print_one(a); + std::cout << " "; + __testlib_print_one(b); + std::cout << " "; + __testlib_print_one(c); + std::cout << " "; + __testlib_print_one(d); + std::cout << " "; + __testlib_print_one(e); + std::cout << std::endl; +} + +template +void println(const A &a, const B &b, const C &c, const D &d, const E &e, const F &f) { + __testlib_print_one(a); + std::cout << " "; + __testlib_print_one(b); + std::cout << " "; + __testlib_print_one(c); + std::cout << " "; + __testlib_print_one(d); + std::cout << " "; + __testlib_print_one(e); + std::cout << " "; + __testlib_print_one(f); + std::cout << std::endl; +} + +template +void println(const A &a, const B &b, const C &c, const D &d, const E &e, const F &f, const G &g) { + __testlib_print_one(a); + std::cout << " "; + __testlib_print_one(b); + std::cout << " "; + __testlib_print_one(c); + std::cout << " "; + __testlib_print_one(d); + std::cout << " "; + __testlib_print_one(e); + std::cout << " "; + __testlib_print_one(f); + std::cout << " "; + __testlib_print_one(g); + std::cout << std::endl; +} + +/* opts */ + +/** + * A struct for a singular testlib opt, containing the raw string value, + * and a boolean value for marking whether the opt is used. + */ +struct TestlibOpt { + std::string value; + bool used; + + TestlibOpt() : value(), used(false) {} +}; + +/** + * Get the type of opt based on the number of `-` at the beginning and the + * _validity_ of the key name. + * + * A valid key name must start with an alphabetical character. + * + * Returns: 1 if s has one `-` at the beginning, that is, "-keyName". + * 2 if s has two `-` at the beginning, that is, "--keyName". + * 0 otherwise. That is, if s has no `-` at the beginning, or has more + * than 2 at the beginning ("---keyName", "----keyName", ...), or the + * keyName is invalid (the first character is not an alphabetical + * character). + */ +size_t getOptType(char *s) { + if (!s || strlen(s) <= 1) + return 0; + + if (s[0] == '-') { + if (isalpha(s[1])) + return 1; + else if (s[1] == '-') + return isalpha(s[2]) ? 2 : 0; + } + + return 0; +} + +/** + * Parse the opt at a given index, and put it into the opts maps. + * + * An opt can has the following form: + * 1) -keyName=value or --keyName=value (ex. -n=10 --test-count=20) + * 2) -keyName value or --keyName value (ex. -n 10 --test-count 20) + * 3) -kNumval or --kNumval (ex. -n10 --t20) + * 4) -boolProperty or --boolProperty (ex. -sorted --tree-only) + * + * Only the second form consumes 2 arguments. The other consumes only 1 + * argument. + * + * In the third form, the key is a single character, and after the key is the + * value. The value _should_ be a number. + * + * In the forth form, the value is true. + * + * Params: + * - argc and argv: the number of command line arguments and the command line + * arguments themselves. + * - index: the starting index of the opts. + * - opts: the map containing the resulting opt. + * + * Returns: the number of consumed arguments to parse the opt. + * 0 if there is no arguments to parse. + * + * Algorithm details: + * TODO. Please refer to the implementation to see how the code handles the 3rd and 4th forms separately. + */ +size_t parseOpt(size_t argc, char *argv[], size_t index, std::map &opts) { + if (index >= argc) + return 0; + + size_t type = getOptType(argv[index]), inc = 1; + if (type > 0) { + std::string key(argv[index] + type), val; + size_t sep = key.find('='); + if (sep != std::string::npos) { + val = key.substr(sep + 1); + key = key.substr(0, sep); + } else { + if (index + 1 < argc && getOptType(argv[index + 1]) == 0) { + val = argv[index + 1]; + inc = 2; + } else { + if (key.length() > 1 && isdigit(key[1])) { + val = key.substr(1); + key = key.substr(0, 1); + } else { + val = "true"; + } + } + } + opts[key].value = val; + } else { + return inc; + } + + return inc; +} + +/** + * Global list containing all the arguments in the order given in the command line. + */ +std::vector __testlib_argv; + +/** + * Global dictionary containing all the parsed opts. + */ +std::map __testlib_opts; + +/** + * Whether automatic no unused opts ensurement should be done. This flag will + * be turned on when `has_opt` or `opt(key, default_value)` is called. + * + * The automatic ensurement can be suppressed when + * __testlib_ensureNoUnusedOptsSuppressed is true. + */ +bool __testlib_ensureNoUnusedOptsFlag = false; + +/** + * Suppress no unused opts automatic ensurement. Can be set to true with + * `suppressEnsureNoUnusedOpts()`. + */ +bool __testlib_ensureNoUnusedOptsSuppressed = false; + +/** + * Parse command line arguments into opts. + * The results are stored into __testlib_argv and __testlib_opts. + */ +void prepareOpts(int argc, char *argv[]) { + if (argc <= 0) + __testlib_fail("Opts: expected argc>=0 but found " + toString(argc)); + size_t n = static_cast(argc); // NOLINT(hicpp-use-auto,modernize-use-auto) + __testlib_opts = std::map(); + for (size_t index = 1; index < n; index += parseOpt(n, argv, index, __testlib_opts)); + __testlib_argv = std::vector(n); + for (size_t index = 0; index < n; index++) + __testlib_argv[index] = argv[index]; +} + +/** + * An utility function to get the argument with a given index. This function + * also print a readable message when no arguments are found. + */ +std::string __testlib_indexToArgv(int index) { + if (index < 0 || index >= int(__testlib_argv.size())) + __testlib_fail("Opts: index '" + toString(index) + "' is out of range [0," + + toString(__testlib_argv.size()) + ")"); + return __testlib_argv[size_t(index)]; +} + +/** + * An utility function to get the opt with a given key . This function + * also print a readable message when no opts are found. + */ +std::string __testlib_keyToOpts(const std::string &key) { + auto it = __testlib_opts.find(key); + if (it == __testlib_opts.end()) + __testlib_fail("Opts: unknown key '" + compress(key) + "'"); + it->second.used = true; + return it->second.value; +} + +template +T optValueToIntegral(const std::string &s, bool nonnegative); + +long double optValueToLongDouble(const std::string &s); + +std::string parseExponentialOptValue(const std::string &s) { + size_t pos = std::string::npos; + for (size_t i = 0; i < s.length(); i++) + if (s[i] == 'e' || s[i] == 'E') { + if (pos != std::string::npos) + __testlib_fail("Opts: expected typical exponential notation but '" + compress(s) + "' found"); + pos = i; + } + if (pos == std::string::npos) + return s; + std::string e = s.substr(pos + 1); + if (!e.empty() && e[0] == '+') + e = e.substr(1); + if (e.empty()) + __testlib_fail("Opts: expected typical exponential notation but '" + compress(s) + "' found"); + if (e.length() > 20) + __testlib_fail("Opts: expected typical exponential notation but '" + compress(s) + "' found"); + int ne = optValueToIntegral(e, false); + std::string num = s.substr(0, pos); + if (num.length() > 20) + __testlib_fail("Opts: expected typical exponential notation but '" + compress(s) + "' found"); + if (!num.empty() && num[0] == '+') + num = num.substr(1); + optValueToLongDouble(num); + bool minus = false; + if (num[0] == '-') { + minus = true; + num = num.substr(1); + } + for (int i = 0; i < +ne; i++) { + size_t sep = num.find('.'); + if (sep == std::string::npos) + num += '0'; + else { + if (sep + 1 == num.length()) + num[sep] = '0'; + else + std::swap(num[sep], num[sep + 1]); + } + } + for (int i = 0; i < -ne; i++) { + size_t sep = num.find('.'); + if (sep == std::string::npos) + num.insert(num.begin() + int(num.length()) - 1, '.'); + else { + if (sep == 0) + num.insert(num.begin() + 1, '0'); + else + std::swap(num[sep - 1], num[sep]); + } + } + while (!num.empty() && num[0] == '0') + num = num.substr(1); + while (num.find('.') != std::string::npos && num.back() == '0') + num = num.substr(0, num.length() - 1); + if (!num.empty() && num.back() == '.') + num = num.substr(0, num.length() - 1); + if ((!num.empty() && num[0] == '.') || num.empty()) + num.insert(num.begin(), '0'); + return (minus ? "-" : "") + num; +} + +template +T optValueToIntegral(const std::string &s_, bool nonnegative) { + std::string s(parseExponentialOptValue(s_)); + if (s.empty()) + __testlib_fail("Opts: expected integer but '" + compress(s_) + "' found"); + T value = 0; + long double about = 0.0; + signed char sign = +1; + size_t pos = 0; + if (s[pos] == '-') { + if (nonnegative) + __testlib_fail("Opts: expected non-negative integer but '" + compress(s_) + "' found"); + sign = -1; + pos++; + } + for (size_t i = pos; i < s.length(); i++) { + if (s[i] < '0' || s[i] > '9') + __testlib_fail("Opts: expected integer but '" + compress(s_) + "' found"); + value = value * 10 + s[i] - '0'; + about = about * 10 + s[i] - '0'; + } + value *= sign; + about *= sign; + if (fabsl(value - about) > 0.1) + __testlib_fail("Opts: integer overflow: expected integer but '" + compress(s_) + "' found"); + return value; +} + +long double optValueToLongDouble(const std::string &s_) { + std::string s(parseExponentialOptValue(s_)); + if (s.empty()) + __testlib_fail("Opts: expected float number but '" + compress(s_) + "' found"); + long double value = 0.0; + signed char sign = +1; + size_t pos = 0; + if (s[pos] == '-') { + sign = -1; + pos++; + } + bool period = false; + long double mul = 1.0; + for (size_t i = pos; i < s.length(); i++) { + if (s[i] == '.') { + if (period) + __testlib_fail("Opts: expected float number but '" + compress(s_) + "' found"); + else { + period = true; + continue; + } + } + if (period) + mul *= 10.0; + if (s[i] < '0' || s[i] > '9') + __testlib_fail("Opts: expected float number but '" + compress(s_) + "' found"); + if (period) + value += (s[i] - '0') / mul; + else + value = value * 10 + s[i] - '0'; + } + value *= sign; + return value; +} + +/** + * Return true if there is an opt with a given key. + * + * By calling this function, automatic ensurement for no unused opts will be + * done when the program is finalized. Call suppressEnsureNoUnusedOpts() to + * turn it off. + */ +bool has_opt(const std::string &key) { + __testlib_ensureNoUnusedOptsFlag = true; + return __testlib_opts.count(key) != 0; +} + +/* About the followings part for opt with 2 and 3 arguments. + * + * To parse the argv/opts correctly for a give type (integer, floating point or + * string), some meta programming must be done to determine the type of + * the type, and use the correct parsing function accordingly. + * + * The pseudo algorithm for determining the type of T and parse it accordingly + * is as follows: + * + * if (T is integral type) { + * if (T is unsigned) { + * parse the argv/opt as an **unsigned integer** of type T. + * } else { + * parse the argv/opt as an **signed integer** of type T. + * } else { + * if (T is floating point type) { + * parse the argv/opt as an **floating point** of type T. + * } else { + * // T should be std::string + * just the raw content of the argv/opts. + * } + * } + * + * To help with meta programming, some `opt` function with 2 or 3 arguments are + * defined. + * + * Opt with 3 arguments: T opt(true/false is_integral, true/false is_unsigned, index/key) + * + * + The first argument is for determining whether the type T is an integral + * type. That is, the result of std::is_integral() should be passed to + * this argument. When false, the type _should_ be either floating point or a + * std::string. + * + * + The second argument is for determining whether the signedness of the type + * T (if it is unsigned or signed). That is, the result of + * std::is_unsigned() should be passed to this argument. This argument can + * be ignored if the first one is false, because it only applies to integer. + * + * Opt with 2 arguments: T opt(true/false is_floating_point, index/key) + * + The first argument is for determining whether the type T is a floating + * point type. That is, the result of std::is_floating_point() should be + * passed to this argument. When false, the type _should_ be a std::string. + */ + +template +T opt(std::false_type is_floating_point, int index); + +template<> +std::string opt(std::false_type /*is_floating_point*/, int index) { + return __testlib_indexToArgv(index); +} + +template +T opt(std::true_type /*is_floating_point*/, int index) { + return T(optValueToLongDouble(__testlib_indexToArgv(index))); +} + +template +T opt(std::false_type /*is_integral*/, U /*is_unsigned*/, int index) { + return opt(std::is_floating_point(), index); +} + +template +T opt(std::true_type /*is_integral*/, std::false_type /*is_unsigned*/, int index) { + return optValueToIntegral(__testlib_indexToArgv(index), false); +} + +template +T opt(std::true_type /*is_integral*/, std::true_type /*is_unsigned*/, int index) { + return optValueToIntegral(__testlib_indexToArgv(index), true); +} + +template<> +bool opt(std::true_type /*is_integral*/, std::true_type /*is_unsigned*/, int index) { + std::string value = __testlib_indexToArgv(index); + if (value == "true" || value == "1") + return true; + if (value == "false" || value == "0") + return false; + __testlib_fail("Opts: opt by index '" + toString(index) + "': expected bool true/false or 0/1 but '" + + compress(value) + "' found"); +} + +/** + * Return the parsed argv by a given index. + */ +template +T opt(int index) { + return opt(std::is_integral(), std::is_unsigned(), index); +} + +/** + * Return the raw string value of an argv by a given index. + */ +std::string opt(int index) { + return opt(index); +} + +/** + * Return the parsed argv by a given index. If the index is bigger than + * the number of argv, return the given default_value. + */ +template +T opt(int index, const T &default_value) { + if (index >= int(__testlib_argv.size())) { + return default_value; + } + return opt(index); +} + +/** + * Return the raw string value of an argv by a given index. If the index is + * bigger than the number of argv, return the given default_value. + */ +std::string opt(int index, const std::string &default_value) { + return opt(index, default_value); +} + +template +T opt(std::false_type is_floating_point, const std::string &key); + +template<> +std::string opt(std::false_type /*is_floating_point*/, const std::string &key) { + return __testlib_keyToOpts(key); +} + +template +T opt(std::true_type /*is_integral*/, const std::string &key) { + return T(optValueToLongDouble(__testlib_keyToOpts(key))); +} + +template +T opt(std::false_type /*is_integral*/, U, const std::string &key) { + return opt(std::is_floating_point(), key); +} + +template +T opt(std::true_type /*is_integral*/, std::false_type /*is_unsigned*/, const std::string &key) { + return optValueToIntegral(__testlib_keyToOpts(key), false); +} + +template +T opt(std::true_type /*is_integral*/, std::true_type /*is_unsigned*/, const std::string &key) { + return optValueToIntegral(__testlib_keyToOpts(key), true); +} + +template<> +bool opt(std::true_type /*is_integral*/, std::true_type /*is_unsigned*/, const std::string &key) { + if (!has_opt(key)) + return false; + std::string value = __testlib_keyToOpts(key); + if (value == "true" || value == "1") + return true; + if (value == "false" || value == "0") + return false; + __testlib_fail("Opts: key '" + compress(key) + "': expected bool true/false or 0/1 but '" + + compress(value) + "' found"); +} + +/** + * Return the parsed opt by a given key. + */ +template +T opt(const std::string &key) { + return opt(std::is_integral(), std::is_unsigned(), key); +} + +/** + * Return the raw string value of an opt by a given key + */ +std::string opt(const std::string &key) { + return opt(key); +} + +/* Scorer started. */ + +enum TestResultVerdict { + SKIPPED, + OK, + WRONG_ANSWER, + RUNTIME_ERROR, + TIME_LIMIT_EXCEEDED, + IDLENESS_LIMIT_EXCEEDED, + MEMORY_LIMIT_EXCEEDED, + COMPILATION_ERROR, + CRASHED, + FAILED +}; + +std::string serializeVerdict(TestResultVerdict verdict) { + switch (verdict) { + case SKIPPED: return "SKIPPED"; + case OK: return "OK"; + case WRONG_ANSWER: return "WRONG_ANSWER"; + case RUNTIME_ERROR: return "RUNTIME_ERROR"; + case TIME_LIMIT_EXCEEDED: return "TIME_LIMIT_EXCEEDED"; + case IDLENESS_LIMIT_EXCEEDED: return "IDLENESS_LIMIT_EXCEEDED"; + case MEMORY_LIMIT_EXCEEDED: return "MEMORY_LIMIT_EXCEEDED"; + case COMPILATION_ERROR: return "COMPILATION_ERROR"; + case CRASHED: return "CRASHED"; + case FAILED: return "FAILED"; + } + throw "Unexpected verdict"; +} + +TestResultVerdict deserializeTestResultVerdict(std::string s) { + if (s == "SKIPPED") + return SKIPPED; + else if (s == "OK") + return OK; + else if (s == "WRONG_ANSWER") + return WRONG_ANSWER; + else if (s == "RUNTIME_ERROR") + return RUNTIME_ERROR; + else if (s == "TIME_LIMIT_EXCEEDED") + return TIME_LIMIT_EXCEEDED; + else if (s == "IDLENESS_LIMIT_EXCEEDED") + return IDLENESS_LIMIT_EXCEEDED; + else if (s == "MEMORY_LIMIT_EXCEEDED") + return MEMORY_LIMIT_EXCEEDED; + else if (s == "COMPILATION_ERROR") + return COMPILATION_ERROR; + else if (s == "CRASHED") + return CRASHED; + else if (s == "FAILED") + return FAILED; + ensuref(false, "Unexpected serialized TestResultVerdict"); + // No return actually. + return FAILED; +} + +struct TestResult { + int testIndex; + std::string testset; + std::string group; + TestResultVerdict verdict; + double points; + long long timeConsumed; + long long memoryConsumed; + std::string input; + std::string output; + std::string answer; + int exitCode; + std::string checkerComment; +}; + +std::string serializePoints(double points) { + if (std::isnan(points)) + return ""; + else { + char c[64]; + sprintf(c, "%.03lf", points); + return c; + } +} + +double deserializePoints(std::string s) { + if (s.empty()) + return std::numeric_limits::quiet_NaN(); + else { + double result; + ensuref(sscanf(s.c_str(), "%lf", &result) == 1, "Invalid serialized points"); + return result; + } +} + +std::string escapeTestResultString(std::string s) { + std::string result; + for (size_t i = 0; i < s.length(); i++) { + if (s[i] == '\r') + continue; + if (s[i] == '\n') { + result += "\\n"; + continue; + } + if (s[i] == '\\' || s[i] == ';') + result += '\\'; + result += s[i]; + } + return result; +} + +std::string unescapeTestResultString(std::string s) { + std::string result; + for (size_t i = 0; i < s.length(); i++) { + if (s[i] == '\\' && i + 1 < s.length()) { + if (s[i + 1] == 'n') { + result += '\n'; + i++; + continue; + } else if (s[i + 1] == ';' || s[i + 1] == '\\') { + result += s[i + 1]; + i++; + continue; + } + } + result += s[i]; + } + return result; +} + +std::string serializeTestResult(TestResult tr) { + std::string result; + result += std::to_string(tr.testIndex); + result += ";"; + result += escapeTestResultString(tr.testset); + result += ";"; + result += escapeTestResultString(tr.group); + result += ";"; + result += serializeVerdict(tr.verdict); + result += ";"; + result += serializePoints(tr.points); + result += ";"; + result += std::to_string(tr.timeConsumed); + result += ";"; + result += std::to_string(tr.memoryConsumed); + result += ";"; + result += escapeTestResultString(tr.input); + result += ";"; + result += escapeTestResultString(tr.output); + result += ";"; + result += escapeTestResultString(tr.answer); + result += ";"; + result += std::to_string(tr.exitCode); + result += ";"; + result += escapeTestResultString(tr.checkerComment); + return result; +} + +TestResult deserializeTestResult(std::string s) { + std::vector items; + std::string t; + for (size_t i = 0; i < s.length(); i++) { + if (s[i] == '\\') { + t += s[i]; + if (i + 1 < s.length()) + t += s[i + 1]; + i++; + continue; + } else { + if (s[i] == ';') { + items.push_back(t); + t = ""; + } else + t += s[i]; + } + } + items.push_back(t); + + ensuref(items.size() == 12, "Invalid TestResult serialization: expected exactly 12 items"); + + TestResult tr; + size_t pos = 0; + tr.testIndex = stoi(items[pos++]); + tr.testset = unescapeTestResultString(items[pos++]); + tr.group = unescapeTestResultString(items[pos++]); + tr.verdict = deserializeTestResultVerdict(items[pos++]); + tr.points = deserializePoints(items[pos++]); + tr.timeConsumed = stoll(items[pos++]); + tr.memoryConsumed = stoll(items[pos++]); + tr.input = unescapeTestResultString(items[pos++]); + tr.output = unescapeTestResultString(items[pos++]); + tr.answer = unescapeTestResultString(items[pos++]); + tr.exitCode = stoi(items[pos++]); + tr.checkerComment = unescapeTestResultString(items[pos++]); + + return tr; +} + +std::vector readTestResults(std::string fileName) { + std::ifstream stream; + stream.open(fileName.c_str(), std::ios::in); + ensuref(stream.is_open(), "Can't read test results file '%s'", fileName.c_str()); + std::vector result; + std::string line; + while (getline(stream, line)) + if (!line.empty()) + result.push_back(deserializeTestResult(line)); + stream.close(); + return result; +} + +std::function)> __testlib_scorer; + +struct TestlibScorerGuard { + ~TestlibScorerGuard() { + if (testlibMode == _scorer) { + std::vector testResults; + while (!inf.eof()) { + std::string line = inf.readLine(); + if (!line.empty()) + testResults.push_back(deserializeTestResult(line)); + } + inf.readEof(); + printf("%.3f\n", __testlib_scorer(testResults)); + } + } +} __testlib_scorer_guard; + +void registerScorer(int argc, char *argv[], std::function)> scorer) { + /* Supress unused. */ + (void)(argc), (void)(argv); + + __testlib_ensuresPreconditions(); + + testlibMode = _scorer; + __testlib_set_binary(stdin); + + inf.init(stdin, _input); + inf.strict = false; + + __testlib_scorer = scorer; +} + +/* Scorer ended. */ + +/** + * Return the parsed opt by a given key. If no opts with the given key are + * found, return the given default_value. + * + * By calling this function, automatic ensurement for no unused opts will be + * done when the program is finalized. Call suppressEnsureNoUnusedOpts() to + * turn it off. + */ +template +T opt(const std::string &key, const T &default_value) { + if (!has_opt(key)) { + return default_value; + } + return opt(key); +} + +/** + * Return the raw string value of an opt by a given key. If no opts with the + * given key are found, return the given default_value. + * + * By calling this function, automatic ensurement for no unused opts will be + * done when the program is finalized. Call suppressEnsureNoUnusedOpts() to + * turn it off. + */ +std::string opt(const std::string &key, const std::string &default_value) { + return opt(key, default_value); +} + +/** + * Check if all opts are used. If not, __testlib_fail is called. + * Should be used after calling all opt() function calls. + * + * This function is useful when opt() with default_value for checking typos + * in the opt's key. + */ +void ensureNoUnusedOpts() { + for (const auto &opt: __testlib_opts) { + if (!opt.second.used) { + __testlib_fail(format("Opts: unused key '%s'", compress(opt.first).c_str())); + } + } +} + +void suppressEnsureNoUnusedOpts() { + __testlib_ensureNoUnusedOptsSuppressed = true; +} + +void TestlibFinalizeGuard::autoEnsureNoUnusedOpts() { + if (__testlib_ensureNoUnusedOptsFlag && !__testlib_ensureNoUnusedOptsSuppressed) { + ensureNoUnusedOpts(); + } +} + +TestlibFinalizeGuard testlibFinalizeGuard; + +#endif +#endif diff --git a/vacations/src/validator.cpp b/vacations/src/validator.cpp new file mode 100644 index 0000000..1ddcffc --- /dev/null +++ b/vacations/src/validator.cpp @@ -0,0 +1,18 @@ +#include "testlib.h" +#include + +using namespace std; + + +int main(int argc, char* argv[]) { + registerValidation(argc, argv); + int n = inf.readInt(1, 100, "n"); + inf.readEoln(); + for (int i = 0; i < n; i++) { + if (i != 0) inf.readSpace(); + inf.readInt(0, 3, "di"); + } + inf.readEoln(); + inf.readEof(); + return 0; +} \ No newline at end of file diff --git a/vacations/statement/description.tex b/vacations/statement/description.tex new file mode 100644 index 0000000..1337f05 --- /dev/null +++ b/vacations/statement/description.tex @@ -0,0 +1,5 @@ +Miguel tem \(n\) dias de férias e pretende aproveitá-los para estudar programação e também praticar esportes. Para cada um desses dias, ele sabe antecipadamente duas informações: se a academia estará aberta e se haverá uma competição online disponível. Assim, cada dia se enquadra em uma das quatro situações possíveis: sem academia e sem competição, sem academia mas com competição, com academia mas sem competição, ou com ambos disponíveis. + +Em cada dia, Miguel deve escolher exatamente uma ação: descansar, participar da competição (caso ele exista naquele dia) ou ir à academia (caso esteja aberta). Seu objetivo é descansar o mínimo possível. No entanto, ele impõe a si mesmo uma regra importante: \textbf{não repetir a mesma atividade em dias consecutivos}. Em outras palavras, Miguel não aceita fazer esporte dois dias seguidos, nem participar de competições em dias consecutivos, embora descansar possa ocorrer repetidamente sem qualquer restrição. + +Dado o calendário das férias, determine o menor número de dias de descanso que Miguel será obrigado a ter. diff --git a/vacations/statement/input.tex b/vacations/statement/input.tex new file mode 100644 index 0000000..05bda2a --- /dev/null +++ b/vacations/statement/input.tex @@ -0,0 +1,9 @@ +A primeira linha contém um inteiro positivo \(n\) (\(1 \le n \le 100\)), o número de dias de férias. + +A segunda linha contém \(n\) inteiros \(a_1, a_2, \dots, a_n\) (\(0 \le a_i \le 3\)), separados por espaços, onde cada \(a_i\) descreve as opções do \(i\)-ésimo dia: +\begin{itemize} + \item \(a_i = 0\): academia fechada e sem competição; + \item \(a_i = 1\): academia fechada e há competição; + \item \(a_i = 2\): academia aberta e sem competição; + \item \(a_i = 3\): academia aberta e há competição. +\end{itemize} \ No newline at end of file diff --git a/vacations/statement/notes.tex b/vacations/statement/notes.tex new file mode 100644 index 0000000..2075db2 --- /dev/null +++ b/vacations/statement/notes.tex @@ -0,0 +1,5 @@ +No primeiro caso de teste, Miguel pode participar da competição no dia 1 e ir à academia no dia 3. Descansando nos dias 2 e 4. + +No segundo caso de teste, Miguel pode participar da competição nos dias 1, 3, 5 e 7 e ir à academia nos demais. + +No terceiro caso de teste, como Miguel não pode ir à academia em dois dias seguidos ele será obrigado a descansar em um dos dias. \ No newline at end of file diff --git a/vacations/statement/output.tex b/vacations/statement/output.tex new file mode 100644 index 0000000..ba2ad98 --- /dev/null +++ b/vacations/statement/output.tex @@ -0,0 +1 @@ +A saída consiste de um único número inteiro, o número mínimo possível de dias em que Miguel terá que descansar, obedecendo à restrição de não repetir a mesma atividade em dias consecutivos. \ No newline at end of file diff --git a/vacations/statement/preamble.tex b/vacations/statement/preamble.tex new file mode 100644 index 0000000..e69de29 diff --git a/vacations/statement/tutorial.tex b/vacations/statement/tutorial.tex new file mode 100644 index 0000000..e69de29 diff --git a/vacations/vacations.pdf b/vacations/vacations.pdf new file mode 100644 index 0000000000000000000000000000000000000000..56225b191d1a5e0ee6958ac560aa91020ef9d12d GIT binary patch literal 87235 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%0D;4V2lI3Af`Su{civCwu2e2(=LScj5&W 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%0A!&>KoC}lhCWQ85) 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 z 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