From 1223e55c4901f6e8d2b03a1196c617e5d34ca41f Mon Sep 17 00:00:00 2001 From: arthur Date: Fri, 19 Dec 2025 07:49:39 -0300 Subject: [PATCH] feat: new dp problem formatted --- longest-palindromic-subsequence/Makefile | 97 + longest-palindromic-subsequence/input/1 | 2 + longest-palindromic-subsequence/input/10 | 2 + longest-palindromic-subsequence/input/11 | 2 + longest-palindromic-subsequence/input/12 | 2 + longest-palindromic-subsequence/input/13 | 2 + longest-palindromic-subsequence/input/14 | 2 + longest-palindromic-subsequence/input/15 | 2 + longest-palindromic-subsequence/input/16 | 2 + longest-palindromic-subsequence/input/17 | 2 + longest-palindromic-subsequence/input/18 | 2 + longest-palindromic-subsequence/input/19 | 2 + longest-palindromic-subsequence/input/2 | 2 + longest-palindromic-subsequence/input/20 | 2 + longest-palindromic-subsequence/input/21 | 2 + longest-palindromic-subsequence/input/22 | 2 + longest-palindromic-subsequence/input/23 | 2 + longest-palindromic-subsequence/input/24 | 2 + longest-palindromic-subsequence/input/25 | 2 + longest-palindromic-subsequence/input/26 | 2 + longest-palindromic-subsequence/input/27 | 2 + longest-palindromic-subsequence/input/28 | 2 + longest-palindromic-subsequence/input/29 | 2 + longest-palindromic-subsequence/input/3 | 2 + longest-palindromic-subsequence/input/30 | 2 + longest-palindromic-subsequence/input/31 | 2 + longest-palindromic-subsequence/input/32 | 2 + longest-palindromic-subsequence/input/33 | 2 + longest-palindromic-subsequence/input/34 | 2 + longest-palindromic-subsequence/input/35 | 2 + longest-palindromic-subsequence/input/4 | 2 + longest-palindromic-subsequence/input/5 | 2 + longest-palindromic-subsequence/input/6 | 2 + longest-palindromic-subsequence/input/7 | 2 + longest-palindromic-subsequence/input/8 | 2 + longest-palindromic-subsequence/input/9 | 2 + .../longest-palindromic-subsequence.pdf | Bin 0 -> 63618 bytes .../longest-palindromic-subsequence.tex | 38 + longest-palindromic-subsequence/maratona.cls | 188 + longest-palindromic-subsequence/output/1 | 1 + longest-palindromic-subsequence/output/10 | 1 + longest-palindromic-subsequence/output/11 | 1 + longest-palindromic-subsequence/output/12 | 1 + longest-palindromic-subsequence/output/13 | 1 + longest-palindromic-subsequence/output/14 | 1 + longest-palindromic-subsequence/output/15 | 1 + longest-palindromic-subsequence/output/16 | 1 + longest-palindromic-subsequence/output/17 | 1 + longest-palindromic-subsequence/output/18 | 1 + longest-palindromic-subsequence/output/19 | 1 + longest-palindromic-subsequence/output/2 | 1 + longest-palindromic-subsequence/output/20 | 1 + longest-palindromic-subsequence/output/21 | 1 + longest-palindromic-subsequence/output/22 | 1 + longest-palindromic-subsequence/output/23 | 1 + longest-palindromic-subsequence/output/24 | 1 + longest-palindromic-subsequence/output/25 | 1 + longest-palindromic-subsequence/output/26 | 1 + longest-palindromic-subsequence/output/27 | 1 + longest-palindromic-subsequence/output/28 | 1 + longest-palindromic-subsequence/output/29 | 1 + longest-palindromic-subsequence/output/3 | 1 + longest-palindromic-subsequence/output/30 | 1 + longest-palindromic-subsequence/output/31 | 1 + longest-palindromic-subsequence/output/32 | 1 + longest-palindromic-subsequence/output/33 | 1 + longest-palindromic-subsequence/output/34 | 1 + longest-palindromic-subsequence/output/35 | 1 + longest-palindromic-subsequence/output/4 | 1 + longest-palindromic-subsequence/output/5 | 1 + longest-palindromic-subsequence/output/6 | 1 + longest-palindromic-subsequence/output/7 | 1 + longest-palindromic-subsequence/output/8 | 1 + longest-palindromic-subsequence/output/9 | 1 + longest-palindromic-subsequence/problem.json | 64 + longest-palindromic-subsequence/src/TLE.cpp | 23 + longest-palindromic-subsequence/src/ac.cpp | 33 + .../src/checker.cpp | 17 + .../src/generator.cpp | 96 + longest-palindromic-subsequence/src/script.sh | 1 + longest-palindromic-subsequence/src/testlib.h | 5963 +++++++++++++++++ .../src/validator.cpp | 16 + .../statement/description.tex | 4 + .../statement/input.tex | 3 + .../statement/notes.tex | 3 + .../statement/output.tex | 1 + .../statement/preamble.tex | 0 .../statement/tutorial.tex | 0 88 files changed, 6652 insertions(+) create mode 100644 longest-palindromic-subsequence/Makefile create mode 100644 longest-palindromic-subsequence/input/1 create mode 100644 longest-palindromic-subsequence/input/10 create mode 100644 longest-palindromic-subsequence/input/11 create mode 100644 longest-palindromic-subsequence/input/12 create mode 100644 longest-palindromic-subsequence/input/13 create mode 100644 longest-palindromic-subsequence/input/14 create mode 100644 longest-palindromic-subsequence/input/15 create mode 100644 longest-palindromic-subsequence/input/16 create mode 100644 longest-palindromic-subsequence/input/17 create mode 100644 longest-palindromic-subsequence/input/18 create mode 100644 longest-palindromic-subsequence/input/19 create mode 100644 longest-palindromic-subsequence/input/2 create mode 100644 longest-palindromic-subsequence/input/20 create mode 100644 longest-palindromic-subsequence/input/21 create mode 100644 longest-palindromic-subsequence/input/22 create mode 100644 longest-palindromic-subsequence/input/23 create mode 100644 longest-palindromic-subsequence/input/24 create mode 100644 longest-palindromic-subsequence/input/25 create mode 100644 longest-palindromic-subsequence/input/26 create mode 100644 longest-palindromic-subsequence/input/27 create mode 100644 longest-palindromic-subsequence/input/28 create mode 100644 longest-palindromic-subsequence/input/29 create mode 100644 longest-palindromic-subsequence/input/3 create mode 100644 longest-palindromic-subsequence/input/30 create mode 100644 longest-palindromic-subsequence/input/31 create mode 100644 longest-palindromic-subsequence/input/32 create mode 100644 longest-palindromic-subsequence/input/33 create mode 100644 longest-palindromic-subsequence/input/34 create mode 100644 longest-palindromic-subsequence/input/35 create mode 100644 longest-palindromic-subsequence/input/4 create mode 100644 longest-palindromic-subsequence/input/5 create mode 100644 longest-palindromic-subsequence/input/6 create mode 100644 longest-palindromic-subsequence/input/7 create mode 100644 longest-palindromic-subsequence/input/8 create mode 100644 longest-palindromic-subsequence/input/9 create mode 100644 longest-palindromic-subsequence/longest-palindromic-subsequence.pdf create mode 100644 longest-palindromic-subsequence/longest-palindromic-subsequence.tex create mode 100644 longest-palindromic-subsequence/maratona.cls create mode 100644 longest-palindromic-subsequence/output/1 create mode 100644 longest-palindromic-subsequence/output/10 create mode 100644 longest-palindromic-subsequence/output/11 create mode 100644 longest-palindromic-subsequence/output/12 create mode 100644 longest-palindromic-subsequence/output/13 create mode 100644 longest-palindromic-subsequence/output/14 create mode 100644 longest-palindromic-subsequence/output/15 create mode 100644 longest-palindromic-subsequence/output/16 create mode 100644 longest-palindromic-subsequence/output/17 create mode 100644 longest-palindromic-subsequence/output/18 create mode 100644 longest-palindromic-subsequence/output/19 create mode 100644 longest-palindromic-subsequence/output/2 create mode 100644 longest-palindromic-subsequence/output/20 create mode 100644 longest-palindromic-subsequence/output/21 create mode 100644 longest-palindromic-subsequence/output/22 create mode 100644 longest-palindromic-subsequence/output/23 create mode 100644 longest-palindromic-subsequence/output/24 create mode 100644 longest-palindromic-subsequence/output/25 create mode 100644 longest-palindromic-subsequence/output/26 create mode 100644 longest-palindromic-subsequence/output/27 create mode 100644 longest-palindromic-subsequence/output/28 create mode 100644 longest-palindromic-subsequence/output/29 create mode 100644 longest-palindromic-subsequence/output/3 create mode 100644 longest-palindromic-subsequence/output/30 create mode 100644 longest-palindromic-subsequence/output/31 create mode 100644 longest-palindromic-subsequence/output/32 create mode 100644 longest-palindromic-subsequence/output/33 create mode 100644 longest-palindromic-subsequence/output/34 create mode 100644 longest-palindromic-subsequence/output/35 create mode 100644 longest-palindromic-subsequence/output/4 create mode 100644 longest-palindromic-subsequence/output/5 create mode 100644 longest-palindromic-subsequence/output/6 create mode 100644 longest-palindromic-subsequence/output/7 create mode 100644 longest-palindromic-subsequence/output/8 create mode 100644 longest-palindromic-subsequence/output/9 create mode 100644 longest-palindromic-subsequence/problem.json create mode 100644 longest-palindromic-subsequence/src/TLE.cpp create mode 100644 longest-palindromic-subsequence/src/ac.cpp create mode 100644 longest-palindromic-subsequence/src/checker.cpp create mode 100644 longest-palindromic-subsequence/src/generator.cpp create mode 100644 longest-palindromic-subsequence/src/script.sh create mode 100644 longest-palindromic-subsequence/src/testlib.h create mode 100644 longest-palindromic-subsequence/src/validator.cpp create mode 100644 longest-palindromic-subsequence/statement/description.tex create mode 100644 longest-palindromic-subsequence/statement/input.tex create mode 100644 longest-palindromic-subsequence/statement/notes.tex create mode 100644 longest-palindromic-subsequence/statement/output.tex create mode 100644 longest-palindromic-subsequence/statement/preamble.tex create mode 100644 longest-palindromic-subsequence/statement/tutorial.tex diff --git a/longest-palindromic-subsequence/Makefile b/longest-palindromic-subsequence/Makefile new file mode 100644 index 0000000..4227f1a --- /dev/null +++ b/longest-palindromic-subsequence/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/longest-palindromic-subsequence/input/1 b/longest-palindromic-subsequence/input/1 new file mode 100644 index 0000000..13128ee --- /dev/null +++ b/longest-palindromic-subsequence/input/1 @@ -0,0 +1,2 @@ +5 +bbbab diff --git a/longest-palindromic-subsequence/input/10 b/longest-palindromic-subsequence/input/10 new file mode 100644 index 0000000..45bc832 --- /dev/null +++ b/longest-palindromic-subsequence/input/10 @@ -0,0 +1,2 @@ +9 +szfwtzfpn diff --git a/longest-palindromic-subsequence/input/11 b/longest-palindromic-subsequence/input/11 new file mode 100644 index 0000000..b3c2293 --- /dev/null +++ b/longest-palindromic-subsequence/input/11 @@ -0,0 +1,2 @@ +8 +mwrccrwm diff --git a/longest-palindromic-subsequence/input/12 b/longest-palindromic-subsequence/input/12 new file mode 100644 index 0000000..08971ba --- /dev/null +++ b/longest-palindromic-subsequence/input/12 @@ -0,0 +1,2 @@ +4 +ivvi diff --git a/longest-palindromic-subsequence/input/13 b/longest-palindromic-subsequence/input/13 new file mode 100644 index 0000000..8f0ee4e --- /dev/null +++ b/longest-palindromic-subsequence/input/13 @@ -0,0 +1,2 @@ +2 +pn diff --git a/longest-palindromic-subsequence/input/14 b/longest-palindromic-subsequence/input/14 new file mode 100644 index 0000000..8f94d44 --- /dev/null +++ b/longest-palindromic-subsequence/input/14 @@ -0,0 +1,2 @@ +100 +uduhznoaquudhavtncwfwujacmiggjmcmkavnjfeodxkgjgwxttxwgjgkxdoefjnbkkmdmjggfmcpjuwlncnrvahduuqaonzhudu diff --git a/longest-palindromic-subsequence/input/15 b/longest-palindromic-subsequence/input/15 new file mode 100644 index 0000000..b74868c --- /dev/null +++ b/longest-palindromic-subsequence/input/15 @@ -0,0 +1,2 @@ +18 +dagktgdarradgtkgdd diff --git a/longest-palindromic-subsequence/input/16 b/longest-palindromic-subsequence/input/16 new file mode 100644 index 0000000..5f237db --- /dev/null +++ b/longest-palindromic-subsequence/input/16 @@ -0,0 +1,2 @@ +58 +stulgbglwmfgzrnyxryetwzhlnfewczmnoozlqatugmdjwgzcfabbkoxyj diff --git a/longest-palindromic-subsequence/input/17 b/longest-palindromic-subsequence/input/17 new file mode 100644 index 0000000..234cb91 --- /dev/null +++ b/longest-palindromic-subsequence/input/17 @@ -0,0 +1,2 @@ +30 +mpprswkdkobdagwdwxsufeesrvncbs diff --git a/longest-palindromic-subsequence/input/18 b/longest-palindromic-subsequence/input/18 new file mode 100644 index 0000000..b40849a --- /dev/null +++ b/longest-palindromic-subsequence/input/18 @@ -0,0 +1,2 @@ +82 +gmkzuzoootorzfskcwbqorvkdrmklfdczezfarqdkkdqhaftazcdflkmrdwvroqbwcksfzrotokozuzbeg diff --git a/longest-palindromic-subsequence/input/19 b/longest-palindromic-subsequence/input/19 new file mode 100644 index 0000000..c5ea9ea --- /dev/null +++ b/longest-palindromic-subsequence/input/19 @@ -0,0 +1,2 @@ +342 +vcvrjcmbqlizvjdwtuyfrxolsysxlfeypoljmqsppmhfkyunyftmwbjxsngxhwzroandfqjamzkattsliljlrkdoytpxugiceakgiakevsjocdmkfnkswrawkjxwcmcciabzbrskkazjqtekiqydptpkcsdgcqjshzndpvannryyrnnavpdnzhsjqcgdsckptpdsqikdtqjzazksrbnbaiccmcwxjkwarwsknfkmdaojsvekaighaechzuxpryljkrldlilsttpkfmgjqfdnaorvjhxgnsxebwmtdynuykfrmppsqmclcpbeflxsysloxrfyutwdjieilybmctrycv diff --git a/longest-palindromic-subsequence/input/2 b/longest-palindromic-subsequence/input/2 new file mode 100644 index 0000000..aa1c0f6 --- /dev/null +++ b/longest-palindromic-subsequence/input/2 @@ -0,0 +1,2 @@ +4 +cbbd diff --git a/longest-palindromic-subsequence/input/20 b/longest-palindromic-subsequence/input/20 new file mode 100644 index 0000000..093e2cc --- /dev/null +++ b/longest-palindromic-subsequence/input/20 @@ -0,0 +1,2 @@ +231 +ikzmnttaifcbopnwezesomkxhaiafmvkbjaisyrbtultpnxbcjmornqumatserhieqggrivouwfnbnghdfallcprvngikcamvprzaeapqmilwkbkgogocniaaisorfqxzjztvcgvzlcedwnezbwxmpobmrvxaskwvvwquudrnwhmmzheqxiwhfuxavlwftgyxxhpygspvwdnvmgnwnpkdrnznzvrkmjjmwisyrd diff --git a/longest-palindromic-subsequence/input/21 b/longest-palindromic-subsequence/input/21 new file mode 100644 index 0000000..fe90722 --- /dev/null +++ b/longest-palindromic-subsequence/input/21 @@ -0,0 +1,2 @@ +593 +fwsjfuvmeewpdwpiymwbhoxebjibxphiefgtsawcdivtltrshjqnkkmdtjgscnozmojnhigippjemzzzbcvoyplxenffmfdzdiojuodgbulvivhtbhayeeebiactyaovqbivudydgxwsgmhlracaayipsojleqhpygshcvxwwlneblfmnqgddqpcjxzftwrlgptrkbkrlwgsnlcaudzdujbbqlfzikgxohvhtuvcjmmwvhkxcgyekjkklcjqoneppydpspiwqbkpsunedqixlsifcokfrcvrszcvdyfwuhtzptbbnxbhqjomxrbhjqxvdaserffcvkecqylqprawyquevhvuzcvfmbewpxicskpmzsbsusmaddqkwgfirlzzbczeghmuhxnxejrspcvqejwowqsfhovhctwnhuuveprriyfwstsjdecyyfjbjsdlegqlklxiyrwvlppomdfdtvtkwokiwwpejxibdknponpsxrytoqgjrtjpatmdlhmqegvjhvlehsykrlvvssmambzusxuszyybdrdvzdbexsglyokvmykifwgfncsacjlkathfmnlctsqejfoxy diff --git a/longest-palindromic-subsequence/input/22 b/longest-palindromic-subsequence/input/22 new file mode 100644 index 0000000..3333c99 --- /dev/null +++ b/longest-palindromic-subsequence/input/22 @@ -0,0 +1,2 @@ +378 +tlhrlypbzisucllqgaaitmxpmfinsowjaawsnmluizvpjbewqcipcqwvsqfbeutdcsdrviozobdytwsimseetqcklnkxtawoxiysvzrakqeispnddxtnfqalswxsmksfooiwxynamdjxnsmkiewkwdpzjpkibcbbmzbiwpmjczcehtczqjzlkgyvszpuuvetdfluuhxpeopuxmdylaysttenjmcedcumoeeicjtxkkvxcxjowrcvlttsqhwkbbmigtqlovjgviyzgcqjvpvotwucsetidicyhtcmajphxyyooeovuxvuploklpbovqdwdypbxgajuqwadgeedjkgurhsxdvylmyfjqlwzldrouylqobsgemwdoibqv diff --git a/longest-palindromic-subsequence/input/23 b/longest-palindromic-subsequence/input/23 new file mode 100644 index 0000000..65597c7 --- /dev/null +++ b/longest-palindromic-subsequence/input/23 @@ -0,0 +1,2 @@ +698 +vqopfhkqmhusxqacoogjxcoxbfzlwcxfvqaavfegkcirqqgdyhljmaqzqifuaoubukypavebvdujgsulahkprfpnzqaqgvfdxwtqflceilpmszizfwbonxplcyqittpkpbcfsesgfbiqnipolefrelphjthqrzsphbnumgrifmwiztfuhqibgaxdvysyvgxlspminykbyumepubrxuoavyovdbielzdobgqcjznjbexalkghywioxzbvxzfcshcozmefwcrvyibjdfqvqmhxdpccjodlgvkplrfdedpzoprfeechwszhvcdooejlchcwcektfrdmowhsueavbrawmihzsnfhrafbqeawdixznppfwieaivtmpqzqtsvnvwjmgvhuesssaxgmoywdgvwiouzuqdebijcqycftaftuwtgxavemciuqmxenprpmyzrexshnvtesstwhytmatxbuzxpstpygfxphpfckjdbfbximeeswyndfhomcnwjtfruvzwbhlzbvebyeucepgcdpmghcibfxgrvnacxwlopxsvzclwymwdmoljtaguwuvhxifdjqshlqaueglqrbxuwpozfvegdpvnwmedxbmxagimxmxgjlnnfkwbrqshxfcanwpoflqejafdktnlpgvlexcyglrzbkhcmxvuobyxcxzxqmlswvlmbvcsdtef diff --git a/longest-palindromic-subsequence/input/24 b/longest-palindromic-subsequence/input/24 new file mode 100644 index 0000000..85636e5 --- /dev/null +++ b/longest-palindromic-subsequence/input/24 @@ -0,0 +1,2 @@ +282 +ilwztbscfhjtcytowmliivrkbblvnmhiprferyrpjpjyochneyffmiegymajrnwjslztbxmduwtfzafkxyfmcnlusebzleggeguujmkyylfmmvviljwgcyhidldkzfzgtzmomlbeqtjsoosjtqebliomftgzfzkdldrhycgwjlivvmmflyykmjuujegyelzbesjlwxmfyxrfazftnudmxbtnlsjknrjamyfeimyfyenhckfjpbpryregrpihmnvlbbrpviilmnotyctjhfcsbtmfli diff --git a/longest-palindromic-subsequence/input/25 b/longest-palindromic-subsequence/input/25 new file mode 100644 index 0000000..2878f5f --- /dev/null +++ b/longest-palindromic-subsequence/input/25 @@ -0,0 +1,2 @@ +104 +mrakgrojgxizwxascasinzxcdxewculofitylhxhzxmjdlisupdylshahcipzoptullyisxsczjqawagnngcggiwkhnarjisvcdpzggt diff --git a/longest-palindromic-subsequence/input/26 b/longest-palindromic-subsequence/input/26 new file mode 100644 index 0000000..5170659 --- /dev/null +++ b/longest-palindromic-subsequence/input/26 @@ -0,0 +1,2 @@ +291 +csjxeubfgyjdimtpftgytkfntylnflbfutsyovxmligoaiqzlxwfrsljucdxssamgcifdljashcjjwhlkqnipxzjglptedzxmthvzgruhhckufdecakrrzoqfqcduzhjsdaskqglqlnnbkuuytqthfcjraawtbccurpzpumcsmqhebhqrfigamblzxycvevluzcuqxvrjgekyaofvrvcohldavkjiykhccmnjpdhkkimpsmvcyqxlgwlbhldkjlzwthkfnizebvlgozrnwwvxdckgnckqtkqidh diff --git a/longest-palindromic-subsequence/input/27 b/longest-palindromic-subsequence/input/27 new file mode 100644 index 0000000..45b60fe --- /dev/null +++ b/longest-palindromic-subsequence/input/27 @@ -0,0 +1,2 @@ +921 +rpkxesldtgxtaurglbgmpyqlpzbnsbzhanbiypuziqurwrbrbxmhbrdpdrerbobajuldlwrpkrtfblspnkxyitiohlpgjlcktlaqsalnoiphbtuyrrghseznkmzukaiihatzttiylactadtninwcsufbynjkxaajnagfevscfuhoajuqmisgbbsxqbylmraszacpliuglqyuzbnizxxjxnntsckjzjzjmmyfmvxjaopvefhwhbyoapkqedyddtrpblporursknpbtamzkkzrrddcmrayglnjuikqynjaucaqekhcwxdqpdohycvaexjyulgvwtovqgsfivkvunqdekhngxjyycspvzulhkywgqjgaqclpsxnserdnrjxrozmxtjtvossyqpvotkhmbqaxiqxuxzlztksohujrtaimpdesfqjbjifgybebnuiicfjteqfvsyrwwjzissaimgcusleiacqxjipdtiljqrbldlirsiewjplnaidvvixjqtqjdozldbbeemvmveqlhjztcouostcgromekrinqbgvgljhveaonqkrtjjtlgbkrnyoixirslfszfqivgkaflgkctvbvksipwomqxlyqxhlbceuhbjbfnhofcgpgwdseffycthmlpcqejgskwjkbkbbmifnurnwyhevsoqzmtvzgfiqajfrgyuzxnrtxectcnlyoisbglpdbjbslxlpoymrcxmdtqhcnlvtqdwftuzgbdxsyscwbrguostbelnvtaqdmkmihmoxqtqlxvlsssisvqvvzotoyqryuyqwoknnqcqggysrqpkrccvyhxsjmhoqoyocwcriplarjoyiqrmmpmueqbsbljddwrumauczfziodpudheexalbwpiypmdjlmwtgdrzhpxneofhqzjdmurgv diff --git a/longest-palindromic-subsequence/input/28 b/longest-palindromic-subsequence/input/28 new file mode 100644 index 0000000..64741e4 --- /dev/null +++ b/longest-palindromic-subsequence/input/28 @@ -0,0 +1,2 @@ +935 +tuwyknlrbvuvtnhiouvqitgyfgfieonbaapyhwpcrmehxcpkijzfiayfvoxkpasyiwxmrahuwlaoovrejhpbiiqmdptefnngfztqhhifmthlxkqbhisdxbgotyspnvusldlfcnogndbcjxqdussoegpwprfussjqhkhbhphtjkywsebaavjaupvdbxfitsyojevycpxwyxfkzdesbnoacixwtrhqhfimukkdinhwyxnjkmopbhoplfmplqjyfiazkxxdmzbnduoaxjdaevibeqacbdxwrgsfvplkhfpnlpflzndtluwrigjjtthzhpowrylzzyvnatbawwxbyduusbdhbggawqvlrbmpgknzvlkeeaveklvqutzzdrqonowwvwjfxxltxmxkkpzkyfzsvyvkvnycvpnpqbribpemmayfpniwazhbjezmenvessyppasifgssfwveuxasvkmpxzvzooptvozcyqpxanftsvgluxxmwtertadxmamtxrdqnploagmmgethvbnexecqidnzpszhlhpsoemjfrdpfawnfhyquwiwnuqztlhklubmjmqimoyumbuprigzzxvkjjoxhyusuklaiympopzyvewmvqmsoisxzuhsqazgggnmruxdkvgpucmtzosjlrpdwaekoxtrawmhijizuqrlnkieylaiiymtdftxjuucjipozzhgbizwmncrcabvmqwafvmuxyybvciurgyaptmpvlcnyuhaytabvkspwisdsdspxysopdemqdgqaxuooompkysokvzzhdpmvnurnaulfutcukwgtxnqxmukbxnlidvysewbwmsnsrfpxxftmjuedksdmnbklsrnjpwvpqwmxxtffgtbdbjifnrvwztbdjrbazxotgfqvyqpgrdojjgjvqiwldvjinoeebscjci diff --git a/longest-palindromic-subsequence/input/29 b/longest-palindromic-subsequence/input/29 new file mode 100644 index 0000000..164ad2b --- /dev/null +++ b/longest-palindromic-subsequence/input/29 @@ -0,0 +1,2 @@ +258 +shvmhycoyszfexxafmkaxsxwrtfcfailjabwunylerasnhszqnhoslthjvsymbzqsjhrllovoyubxmxbyunvaadrvbujhorbyhwunrhnikrhwodlxngpqurfpiqdftenwwseifdqipfruqpgnxldowhrxinxmnuwhybroojkbvrdaavnuybxmxbuyovollrhjsqzbmusvjhtlvohnhashnskrolynuwbajlvafcftkwisxakmbaxxlfzkyocyimvhv diff --git a/longest-palindromic-subsequence/input/3 b/longest-palindromic-subsequence/input/3 new file mode 100644 index 0000000..e439850 --- /dev/null +++ b/longest-palindromic-subsequence/input/3 @@ -0,0 +1,2 @@ +1 +a diff --git a/longest-palindromic-subsequence/input/30 b/longest-palindromic-subsequence/input/30 new file mode 100644 index 0000000..9f7f47a --- /dev/null +++ b/longest-palindromic-subsequence/input/30 @@ -0,0 +1,2 @@ +616 +chqhygftvaofpxwmpmfbcfnclqexjgvzpqbxcqoskjdxwhimeuwxopzafascsxawaroblpmamklrwlznplgspuzvnubpudibptdslaagxaaacqrsfvhclaedsmlkjaqsoqgfpovigxfvhltpwptojsardozogrltulberiywireebjddkdhpyleypylevvglkckubmygxzqmeeyehjehknbkprsvdgjoizzgjszebtaqqgzwyfgdcbkdgxzurjpoahrhdpqexzsrpgvdutabogkwkuehfzwhvamsntzuvcrqzplxhykiaoapjzkznmlsnezsskdlosiyfawaznbuwenovcsfkfuhntglvesxsrrnzkbhzkhzmvkjevsrbdiclckmsgpgngyckzvgysvwcgwayjokqactfxtivfbdwprufivtggzhbpvlxfkisdneogdseenjlewrobjhpppjczyxeaiqanaztksnpfwyhdjvipgwzznmnnxwraiieicscdhryzvrhtoprratxufcithokiogudggzpvjctbahnzdwtokiatsriqzwedrrfzbrkgvynbbfomoiawwmmjiqvhdlnsvwnwbktehykev diff --git a/longest-palindromic-subsequence/input/31 b/longest-palindromic-subsequence/input/31 new file mode 100644 index 0000000..870e681 --- /dev/null +++ b/longest-palindromic-subsequence/input/31 @@ -0,0 +1,2 @@ +446 +flmnkrljmujvfxdvdydmvkjsbpmvgmnfeseumhbdioizcjvpwyxqwdpychqxtfdlkedhujduqbqwxvoxclajstguqnirrpxandmwhlwdygnnordxmujnzlkeamdxaaokvbvplrwxzijpjkulovealuepkslyiuzywpyyfocicazyewqyunjlfcthlieolxuypkqpemzjjpswulkngytffixvoiyuusyytuuyiovxifftygnkluwspjjfmepqkpyuxloeilhtmfljltwyweyzacicofxypwyzuiylskpeuluedolukrajizxwrlpvbvkonhximaeklznjuyxdjonngydwlhwmdncxprrrnqoatsjaljxovxwzbquddbrdeklduscqvcypdsqxyapojcdhoidbhmuestknmgcmpbsjkvmdydvdxfvjimjlrknslf diff --git a/longest-palindromic-subsequence/input/32 b/longest-palindromic-subsequence/input/32 new file mode 100644 index 0000000..795c299 --- /dev/null +++ b/longest-palindromic-subsequence/input/32 @@ -0,0 +1,2 @@ +398 +dnwkyfymgrfmzxqpejcixxppqgvuawutgrmezjkteofjbnrvzzkvjtacfxjjokisavsgrslryxfqgrmdsqwptajbqzvethuljbdatxghfzqrwvfgakwmoawlzqjypmhllbbuuhbpriqsnibywlgjlxowyzagrfnqafvcqwktkcjwejevzbnxhsfmwojshcdypnvbuhhuzqmgovmvgwiizatoxgblyudipahfbkewmuneoqhjmbpdtwnznblwvtjrniwlbyblhppndspojrouffazpoxtqdfpjuhitvijrohavpqatofxwmksvjcvhdecxwwmosqiczjpkfafqlboxosnjgzgdraehzdltthemeusxhiiimrdrugabnxwsygsktkcslhjebfexu diff --git a/longest-palindromic-subsequence/input/33 b/longest-palindromic-subsequence/input/33 new file mode 100644 index 0000000..b524ac5 --- /dev/null +++ b/longest-palindromic-subsequence/input/33 @@ -0,0 +1,2 @@ +694 +wrptebkjhefsvfrmcqqdlanbetrgzwylizmrystvpgrkhlicfadcogtnigdrxaslquolbtomefrtocgsyyxmmsoessjmkvhskploeetlfvcjlilcemzwtvjilgdvbvafaeqqojypxjdyxdzxbtkccesympaxxhzcaqjdoixjiivinpidpfjhvavbwpckqncjwygbbdwbqjvdehkevsntanowlersappruokywnegncmjvjxcsalrmiuszjmkapbwdvdnjxnxrnlmirlmehsayuhjpajkuxsyrirkpmgzcyupoigwsdqsuxmaixwsqgvlrjzfcqrphsbgrsfneaijelhyrumkqpkqklsacnhpznpxzsfgmcoubkpcwzmkmaxjypvswrigsvqgogoqcivazsindehaozddwxttffshovpvpoldlonlkeggvxcyqkabpwnrzejfdopdhxkoqspevrrjeochbdfqbvcoyvffvzauufrrohjtxnjzpmkdkjbfqflivigiwztgbybugifdyhojtjkoaqiehkjmatgyhgkjumwvalsqmcoiijvwchnenikrlizwkhktdxtqvxibctbnbxfudivicnljlnzpghkvjcosvfnryipiiylotxanmkcljvyycmrtscndzivghxaigwxskrksqjokvncectsfxpgyorkufs diff --git a/longest-palindromic-subsequence/input/34 b/longest-palindromic-subsequence/input/34 new file mode 100644 index 0000000..4148e6a --- /dev/null +++ b/longest-palindromic-subsequence/input/34 @@ -0,0 +1,2 @@ +1000 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/longest-palindromic-subsequence/input/35 b/longest-palindromic-subsequence/input/35 new file mode 100644 index 0000000..a2752cb --- /dev/null +++ b/longest-palindromic-subsequence/input/35 @@ -0,0 +1,2 @@ +1000 +aciqgncvxtghwtpbnfskrmpzcymxugwjdilcorkrzpuewahxylcgnzksusrauptymacgtstkdxwygkdrggmqkomlrwrroqfnzpvwocuaggxcvbflauqxqbwtfyhpeyfdpydbfancnkgtyomyhdodvbiqneqfwsvyfrpijygjduhwaggcwzidphkrwyjcqgzpsrlcjuybmgaorppyffunuonatqseysoubmiafjbzxuiwszuovqewcolejflivckbbwdjgmzvfkxzxfdcxbaymmntielkjnzkoddcpfepdqhgyrawgymamljwnbieawiufaepocjmcsoynmiuplaekaxexiyjfhhgxeqpxsvievrooopkwnvxqazpxldlyeqwduiqurnwsmxxarzoampoqoxcmqgamihmsrjnrlnijtnzxcdyczmyfruwsfkvxvljuporlhzeqqzrlydqlxtgjmxdstcrabjcopybqybaalilyzhysadroqijfhyvgzufdlrzgecmeqtgkfgifpyiehmcgrpopmozmaecxfpkwzeualgfdmdexmksipymegeruxgtganeljamwvtxfqfcehncnhxayvdrkwppxiscaykvmkyjkjjgzidbatjujgdcsoqnlxgxxdeyewhvtncvpusjinbrrjcwfxcafbxpytbeypcoswmpdcbdcmjsfzyoohdzyudjoukiowfcmhpliccyhiigrnjmxyafnxnfzvnbnsxbkampswfmooflqwwdnsajuzisgrzozdgnhhuaibgyctpyqhcxchhygihqaermspsgomqkyltmrfgqbdhiloyxfityhewgmvcakcxunuxogdvurumqogwljlfhysyjvvefpkbyibzeqfjhzymhdkdzueqdhnyvqtunonrxjnfbrukwlfitfmovpqnrohznpyfcozugjybluvniqukmswcwsriwfqnhotbayaeqvyphrkwutqicjowqmqne diff --git a/longest-palindromic-subsequence/input/4 b/longest-palindromic-subsequence/input/4 new file mode 100644 index 0000000..d19826c --- /dev/null +++ b/longest-palindromic-subsequence/input/4 @@ -0,0 +1,2 @@ +2 +we diff --git a/longest-palindromic-subsequence/input/5 b/longest-palindromic-subsequence/input/5 new file mode 100644 index 0000000..fabdac6 --- /dev/null +++ b/longest-palindromic-subsequence/input/5 @@ -0,0 +1,2 @@ +4 +dttd diff --git a/longest-palindromic-subsequence/input/6 b/longest-palindromic-subsequence/input/6 new file mode 100644 index 0000000..0724b26 --- /dev/null +++ b/longest-palindromic-subsequence/input/6 @@ -0,0 +1,2 @@ +9 +gmdbyfwur diff --git a/longest-palindromic-subsequence/input/7 b/longest-palindromic-subsequence/input/7 new file mode 100644 index 0000000..69db38e --- /dev/null +++ b/longest-palindromic-subsequence/input/7 @@ -0,0 +1,2 @@ +8 +vhiffihv diff --git a/longest-palindromic-subsequence/input/8 b/longest-palindromic-subsequence/input/8 new file mode 100644 index 0000000..c2dc435 --- /dev/null +++ b/longest-palindromic-subsequence/input/8 @@ -0,0 +1,2 @@ +10 +yndmhtqvkg diff --git a/longest-palindromic-subsequence/input/9 b/longest-palindromic-subsequence/input/9 new file mode 100644 index 0000000..3003771 --- /dev/null +++ b/longest-palindromic-subsequence/input/9 @@ -0,0 +1,2 @@ +10 +tsaottozst diff --git a/longest-palindromic-subsequence/longest-palindromic-subsequence.pdf b/longest-palindromic-subsequence/longest-palindromic-subsequence.pdf new file mode 100644 index 0000000000000000000000000000000000000000..794ecd4460e01f9359c1fb9778ec2f2561b9d8b8 GIT binary patch literal 63618 zcmb4rWn9(U7A@V~-Cgd@rn@^Oq`Rd-knWTgB%~XZMg)}ZZV5p^0V!#u*>8J}_ulur zXTNuGe}ZrSHP%{ljxpw(i%~;HjuXhmi^e!P+qZzmO9P;Bv2Z{W5kY&TV(o0}X-5O( z=LOOH^+S6kXYc4~?N0MZ&e7b{TE^Pa#mX8@ObpG#)7{$K3GMk(mEMZWXFi;u3sc$+ zMI?)a)l{_of|XV{+4s*Be$JkSG^NT!STm)p5Z>&04-`=>>c$bQC|gk_4y*=H_cVNn zvpuwNskRlrD}Bx+!0y9ZzxR1`XtW}fP}gQ&=O-)p+@W1VX{#fA%!uf!>EOLgb1pF( z_GyHtkKV=U#QdSHOO0(J2sTBM4t07oRkq2&Hc#yIE!_1@90;*Ei0;X2`=X2~w7{B% zH;bmA+$7Np#$ImxEY^4u7my|jQ}GbR_fZAq+Mo;7ZJ6?BS98vb^NAnGtv77uo--`n zelt2=u6eCGx5Dz~v(2U^Vp3H@XxgV;JB;zhrbQ_MT{hViaUQ3JDoLe^Q?@`%y^;Wl zHyi77{;(wOxR`j@WVH3NuqfxpJ}<}jK2{k@6two2olY;Tt};kCASk4(2z#JxpF5Mc zK8d;NOh?x&gdcXK#RQ4KUV5}oc5h-E>s9Z4nsFfH3z(tjGMe*9et*_b`Tp5FANlH( z(D8dK)7wSr&-_Z_^-d`frmqjT(31}B-CSSA*+>dD3Ps8(=I@jbOQsGAcfe^po7h4( z%(!*ID=AGHq|gm*a*>|DW=jsBv3T+x7XF6)zCxJp-q1T_p*w*k-$gx@EKXONtJ$9% zuY&AATsPt+UZf|Au?KRbk!k2m4(tJu<&*?TC|`R~r^+#DYituIjnR$M=`-iiTK)CD zOL_~~Fp;hT_`6Toi)eh@OB*%zZ}NsCkhO`LpM2oTVm8ryDcSFU(Y`&UQi&i=*Uc?N z&OmnLZP&xN2!|OZ5^&eYJZ)mLw7u=AB`bjIfQDqr7c1G*p6?-g;UCAN~tHuW%F0Ui+u&kD(2v+5Ki z83J9GU3+2_sZgd>V%^Q~dJ8r)ip*L8>K4Vh-SBF_Zi+6!R4wjrv08#Bage|Brd7~% zqmw!4xhkrq*{x&Kqq-L6qy+|8s#!*9qy+;k+}Jxe)tc(q=wtA*r1?nS&;%|hvbaz$O(Kv2|G``ip|$kBe{ z`(|&%CxFg&Lx{EH+L!C})VHjvMoRb$CC}vFJj2{c<8F5$)Xxq*F)x z`ACN4IiCuX7!QT+EBVZz%{tkS0zWWE342iW7HPka*^l>Zv3!rGAD|_@B_CnsquD_y zsiB?Y8)KVvNF7baerm327}X^x`$83MXeZ3t-$Q)o!%)jsPpW9=E2F~~(rF^ERq&?S7cJdhPZx-~dKh7SM!>Pbv(snU`I4eXR-JcZ(;am^v0MU8Olj@# zgMIj8srpyZI6IFGw$?OL!=F9#681gJ?n3(BsMzp9ET{o5Qqbh~Xb#PxnR9=A<;2>+ z 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 literal 0 HcmV?d00001 diff --git a/longest-palindromic-subsequence/longest-palindromic-subsequence.tex b/longest-palindromic-subsequence/longest-palindromic-subsequence.tex new file mode 100644 index 0000000..f6b586a --- /dev/null +++ b/longest-palindromic-subsequence/longest-palindromic-subsequence.tex @@ -0,0 +1,38 @@ +\documentclass{maratona} + +\begin{document} +\begin{ProblemaAutor}{}{Maior Subsequência Palindrômica}{1}{256}{} + +O problema consiste em determinar a maior subsequência palindrômica de uma sequência de caracteres. +Uma subsequência é formada ao remover zero ou mais elementos da sequência original, sem alterar a ordem relativa dos elementos restantes. +A subsequência procurada deve ser um palíndromo, ou seja, deve ser idêntica quando lida de frente para trás ou de trás para frente. +O objetivo é identificar essa subsequência de tamanho máximo e apresentar tanto o seu comprimento quanto os próprios elementos. + +\Entrada + +A entrada é composta por duas linhas. +A primeira linha contém um inteiro \( n \) (\( 1 \leq n \leq 1000 \)), representando o número de caracteres da sequência. +A segunda linha contém uma string \( s \) de comprimento \( n \), composta por letras minúsculas do alfabeto. + +\Saida + +A saída é composta por uma linha, um único inteiro, que representa representando o tamanho \( L \) da maior subsequência palindrômica. + +\ExemploEntrada +\begin{Exemplo} +\texttt{5} & \texttt{4}\\ +\texttt{bbbab} & \\ +\rowcolor{gray!20}\texttt{4} & \texttt{2}\\ +\rowcolor{gray!20}\texttt{cbbd} & \\ +\texttt{1} & \texttt{1}\\ +\texttt{a} & \\ +\end{Exemplo} + + + +\Notas + +Para a sequência "bbbab", o tamanho da maior subsequência palindrômica é \( L = 4 \) e uma possível sequência é "bbbb". +Para a sequência "cbbd", a maior subsequência palindrômica é "bb", com tamanho \( L = 2 \). +Para a sequência "a", há apenas um elemento, então a maior subsequência palindrômica é o próprio caractere "a", com tamanho \( L = 1 \).\end{ProblemaAutor} +\end{document} diff --git a/longest-palindromic-subsequence/maratona.cls b/longest-palindromic-subsequence/maratona.cls new file mode 100644 index 0000000..e11d53d --- /dev/null +++ b/longest-palindromic-subsequence/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/longest-palindromic-subsequence/output/1 b/longest-palindromic-subsequence/output/1 new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/longest-palindromic-subsequence/output/1 @@ -0,0 +1 @@ +4 diff --git a/longest-palindromic-subsequence/output/10 b/longest-palindromic-subsequence/output/10 new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/longest-palindromic-subsequence/output/10 @@ -0,0 +1 @@ +3 diff --git a/longest-palindromic-subsequence/output/11 b/longest-palindromic-subsequence/output/11 new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/longest-palindromic-subsequence/output/11 @@ -0,0 +1 @@ +8 diff --git a/longest-palindromic-subsequence/output/12 b/longest-palindromic-subsequence/output/12 new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/longest-palindromic-subsequence/output/12 @@ -0,0 +1 @@ +4 diff --git a/longest-palindromic-subsequence/output/13 b/longest-palindromic-subsequence/output/13 new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/longest-palindromic-subsequence/output/13 @@ -0,0 +1 @@ +1 diff --git a/longest-palindromic-subsequence/output/14 b/longest-palindromic-subsequence/output/14 new file mode 100644 index 0000000..871727d --- /dev/null +++ b/longest-palindromic-subsequence/output/14 @@ -0,0 +1 @@ +84 diff --git a/longest-palindromic-subsequence/output/15 b/longest-palindromic-subsequence/output/15 new file mode 100644 index 0000000..b6a7d89 --- /dev/null +++ b/longest-palindromic-subsequence/output/15 @@ -0,0 +1 @@ +16 diff --git a/longest-palindromic-subsequence/output/16 b/longest-palindromic-subsequence/output/16 new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/longest-palindromic-subsequence/output/16 @@ -0,0 +1 @@ +18 diff --git a/longest-palindromic-subsequence/output/17 b/longest-palindromic-subsequence/output/17 new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/longest-palindromic-subsequence/output/17 @@ -0,0 +1 @@ +9 diff --git a/longest-palindromic-subsequence/output/18 b/longest-palindromic-subsequence/output/18 new file mode 100644 index 0000000..38b10c1 --- /dev/null +++ b/longest-palindromic-subsequence/output/18 @@ -0,0 +1 @@ +68 diff --git a/longest-palindromic-subsequence/output/19 b/longest-palindromic-subsequence/output/19 new file mode 100644 index 0000000..c20f657 --- /dev/null +++ b/longest-palindromic-subsequence/output/19 @@ -0,0 +1 @@ +286 diff --git a/longest-palindromic-subsequence/output/2 b/longest-palindromic-subsequence/output/2 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/longest-palindromic-subsequence/output/2 @@ -0,0 +1 @@ +2 diff --git a/longest-palindromic-subsequence/output/20 b/longest-palindromic-subsequence/output/20 new file mode 100644 index 0000000..39f5b69 --- /dev/null +++ b/longest-palindromic-subsequence/output/20 @@ -0,0 +1 @@ +71 diff --git a/longest-palindromic-subsequence/output/21 b/longest-palindromic-subsequence/output/21 new file mode 100644 index 0000000..aa34eab --- /dev/null +++ b/longest-palindromic-subsequence/output/21 @@ -0,0 +1 @@ +199 diff --git a/longest-palindromic-subsequence/output/22 b/longest-palindromic-subsequence/output/22 new file mode 100644 index 0000000..5bc6609 --- /dev/null +++ b/longest-palindromic-subsequence/output/22 @@ -0,0 +1 @@ +117 diff --git a/longest-palindromic-subsequence/output/23 b/longest-palindromic-subsequence/output/23 new file mode 100644 index 0000000..5f277ae --- /dev/null +++ b/longest-palindromic-subsequence/output/23 @@ -0,0 +1 @@ +223 diff --git a/longest-palindromic-subsequence/output/24 b/longest-palindromic-subsequence/output/24 new file mode 100644 index 0000000..1cf253f --- /dev/null +++ b/longest-palindromic-subsequence/output/24 @@ -0,0 +1 @@ +238 diff --git a/longest-palindromic-subsequence/output/25 b/longest-palindromic-subsequence/output/25 new file mode 100644 index 0000000..8f92bfd --- /dev/null +++ b/longest-palindromic-subsequence/output/25 @@ -0,0 +1 @@ +35 diff --git a/longest-palindromic-subsequence/output/26 b/longest-palindromic-subsequence/output/26 new file mode 100644 index 0000000..c67f579 --- /dev/null +++ b/longest-palindromic-subsequence/output/26 @@ -0,0 +1 @@ +93 diff --git a/longest-palindromic-subsequence/output/27 b/longest-palindromic-subsequence/output/27 new file mode 100644 index 0000000..03a5b41 --- /dev/null +++ b/longest-palindromic-subsequence/output/27 @@ -0,0 +1 @@ +299 diff --git a/longest-palindromic-subsequence/output/28 b/longest-palindromic-subsequence/output/28 new file mode 100644 index 0000000..9530e04 --- /dev/null +++ b/longest-palindromic-subsequence/output/28 @@ -0,0 +1 @@ +296 diff --git a/longest-palindromic-subsequence/output/29 b/longest-palindromic-subsequence/output/29 new file mode 100644 index 0000000..a817176 --- /dev/null +++ b/longest-palindromic-subsequence/output/29 @@ -0,0 +1 @@ +216 diff --git a/longest-palindromic-subsequence/output/3 b/longest-palindromic-subsequence/output/3 new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/longest-palindromic-subsequence/output/3 @@ -0,0 +1 @@ +1 diff --git a/longest-palindromic-subsequence/output/30 b/longest-palindromic-subsequence/output/30 new file mode 100644 index 0000000..6bb2f98 --- /dev/null +++ b/longest-palindromic-subsequence/output/30 @@ -0,0 +1 @@ +195 diff --git a/longest-palindromic-subsequence/output/31 b/longest-palindromic-subsequence/output/31 new file mode 100644 index 0000000..cb35cf9 --- /dev/null +++ b/longest-palindromic-subsequence/output/31 @@ -0,0 +1 @@ +368 diff --git a/longest-palindromic-subsequence/output/32 b/longest-palindromic-subsequence/output/32 new file mode 100644 index 0000000..a57f6ce --- /dev/null +++ b/longest-palindromic-subsequence/output/32 @@ -0,0 +1 @@ +131 diff --git a/longest-palindromic-subsequence/output/33 b/longest-palindromic-subsequence/output/33 new file mode 100644 index 0000000..71d936f --- /dev/null +++ b/longest-palindromic-subsequence/output/33 @@ -0,0 +1 @@ +231 diff --git a/longest-palindromic-subsequence/output/34 b/longest-palindromic-subsequence/output/34 new file mode 100644 index 0000000..83b33d2 --- /dev/null +++ b/longest-palindromic-subsequence/output/34 @@ -0,0 +1 @@ +1000 diff --git a/longest-palindromic-subsequence/output/35 b/longest-palindromic-subsequence/output/35 new file mode 100644 index 0000000..27a69f6 --- /dev/null +++ b/longest-palindromic-subsequence/output/35 @@ -0,0 +1 @@ +327 diff --git a/longest-palindromic-subsequence/output/4 b/longest-palindromic-subsequence/output/4 new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/longest-palindromic-subsequence/output/4 @@ -0,0 +1 @@ +1 diff --git a/longest-palindromic-subsequence/output/5 b/longest-palindromic-subsequence/output/5 new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/longest-palindromic-subsequence/output/5 @@ -0,0 +1 @@ +4 diff --git a/longest-palindromic-subsequence/output/6 b/longest-palindromic-subsequence/output/6 new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/longest-palindromic-subsequence/output/6 @@ -0,0 +1 @@ +1 diff --git a/longest-palindromic-subsequence/output/7 b/longest-palindromic-subsequence/output/7 new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/longest-palindromic-subsequence/output/7 @@ -0,0 +1 @@ +8 diff --git a/longest-palindromic-subsequence/output/8 b/longest-palindromic-subsequence/output/8 new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/longest-palindromic-subsequence/output/8 @@ -0,0 +1 @@ +1 diff --git a/longest-palindromic-subsequence/output/9 b/longest-palindromic-subsequence/output/9 new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/longest-palindromic-subsequence/output/9 @@ -0,0 +1 @@ +8 diff --git a/longest-palindromic-subsequence/problem.json b/longest-palindromic-subsequence/problem.json new file mode 100644 index 0000000..4cf7e73 --- /dev/null +++ b/longest-palindromic-subsequence/problem.json @@ -0,0 +1,64 @@ +{ + "version": "1.0", + "problem": { + "title": "Maior Subsequência Palindrômica", + "event": "", + "time_limit": 1.0, + "memory_limit_mb": 256, + "input_file": "stdin", + "output_file": "stdout", + "interactive": false, + "grader": false, + "subject": { + "en_us": [ + "dynamic-programming", "DP", "longest-palindromic-subsequence", "LPS" + ], + "pt_br": [ + "programação-dinâmica", "maior-subsequência-palindrômica" + ], + "es": [ + "" + ] + } + }, + "author": { + "name": "", + "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/longest-palindromic-subsequence/src/TLE.cpp b/longest-palindromic-subsequence/src/TLE.cpp new file mode 100644 index 0000000..05c410e --- /dev/null +++ b/longest-palindromic-subsequence/src/TLE.cpp @@ -0,0 +1,23 @@ +#include + +using namespace std; + +int solve(const string& s) { + if (s.length() == 0) return 0; + if (s.length() == 1) return 1; + + if (s.front() == s.back()) { + return 2 + solve(s.substr(1, s.length() - 2)); + } else { + return max(solve(s.substr(1)), solve(s.substr(0, s.length() - 1))); + } +} + +int main() { + int n; cin >> n; + string s; cin >> s; + + cout << solve(s) << endl; + + return 0; +} \ No newline at end of file diff --git a/longest-palindromic-subsequence/src/ac.cpp b/longest-palindromic-subsequence/src/ac.cpp new file mode 100644 index 0000000..9720f59 --- /dev/null +++ b/longest-palindromic-subsequence/src/ac.cpp @@ -0,0 +1,33 @@ +#include + +using namespace std; + +int main() +{ + int n; cin >> n; + string s; cin >> s; + + /* + dp[i][j] says if the substring from i to j is a palindrome + */ + vector> dp(n, vector(n, 0)); + for (int i = n - 1; i >= 0; i--) + { + dp[i][i] = 1; + for (int j = i + 1; j < n; j++) + { + if (s[i] == s[j]) + { + dp[i][j] = dp[i + 1][j - 1] + 2; + } + else + { + dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); + } + } + } + + cout << dp[0][n - 1] << endl; + + return 0; +} \ No newline at end of file diff --git a/longest-palindromic-subsequence/src/checker.cpp b/longest-palindromic-subsequence/src/checker.cpp new file mode 100644 index 0000000..f85c1aa --- /dev/null +++ b/longest-palindromic-subsequence/src/checker.cpp @@ -0,0 +1,17 @@ +#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, "all answers are correct"); +} \ No newline at end of file diff --git a/longest-palindromic-subsequence/src/generator.cpp b/longest-palindromic-subsequence/src/generator.cpp new file mode 100644 index 0000000..17ed152 --- /dev/null +++ b/longest-palindromic-subsequence/src/generator.cpp @@ -0,0 +1,96 @@ +#include "testlib.h" +#include + +using namespace std; + +const int MIN_N = 1; +const int MAX_N = 1000; +const int rnd_test_n = 30; + +template void append(vector &dest, const vector &orig) { + dest.insert(dest.end(), orig.begin(), orig.end()); +} + +string output_tc(const string &s) { + ostringstream oss; + oss << s.size() << endl; + oss << s << endl; + return oss.str(); +} + +vector generate_sample_tests() { + vector tests; + tests.push_back(output_tc("bbbab")); + tests.push_back(output_tc("cbbd")); + tests.push_back(output_tc("a")); + return tests; +} + +vector generate_manual_tests() { + vector tests; + return tests; +} + +string generate_structured_string(int n) { + string s = ""; + + if (rnd.next(0, 1) == 1) { + string half = rnd.next("[a-z]{" + to_string((n + 1) / 2) + "}"); + s = half; + reverse(half.begin(), half.end()); + s += half; + for (int i = 0; i < n / 10; i++) { + s[rnd.next(0, n - 1)] = rnd.next('a', 'z'); + } + } + else { + s = rnd.next("[a-z]{" + to_string(n) + "}"); + } + return s; +} + +string rnd_test(int i) { + int min_n = MIN_N; + int max_n = MAX_N; + + if (i < rnd_test_n / 3) { + max_n = 10; + } else if (i < rnd_test_n / 2) { + max_n = 100; + } + + int n = rnd.next(min_n, max_n); + return output_tc(generate_structured_string(n)); +} + +vector generate_random_tests() { + vector tests; + for (int i = 0; i < rnd_test_n; i++) { + tests.push_back(rnd_test(i)); + } + return tests; +} + +vector generate_extreme_tests() { + vector tests; + tests.push_back(output_tc(string(1000, 'a'))); + tests.push_back(output_tc(rnd.next("[a-z]{1000}"))); + 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/longest-palindromic-subsequence/src/script.sh b/longest-palindromic-subsequence/src/script.sh new file mode 100644 index 0000000..a8a6bda --- /dev/null +++ b/longest-palindromic-subsequence/src/script.sh @@ -0,0 +1 @@ +generator \ No newline at end of file diff --git a/longest-palindromic-subsequence/src/testlib.h b/longest-palindromic-subsequence/src/testlib.h new file mode 100644 index 0000000..fac02ad --- /dev/null +++ b/longest-palindromic-subsequence/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/longest-palindromic-subsequence/src/validator.cpp b/longest-palindromic-subsequence/src/validator.cpp new file mode 100644 index 0000000..36f7f68 --- /dev/null +++ b/longest-palindromic-subsequence/src/validator.cpp @@ -0,0 +1,16 @@ +#include "testlib.h" +#include + +using namespace std; + + +int main(int argc, char* argv[]) { + registerValidation(argc, argv); + int n = inf.readInt(1, 1000); + inf.readEoln(); + string s = inf.readToken("[a-z]+"); + ensuref(n == (int)s.size(), "string provided %s does not have %i characters", s, n); + inf.readEoln(); + inf.readEof(); + return 0; +} \ No newline at end of file diff --git a/longest-palindromic-subsequence/statement/description.tex b/longest-palindromic-subsequence/statement/description.tex new file mode 100644 index 0000000..8e24af2 --- /dev/null +++ b/longest-palindromic-subsequence/statement/description.tex @@ -0,0 +1,4 @@ +O problema consiste em determinar a maior subsequência palindrômica de uma sequência de caracteres. +Uma subsequência é formada ao remover zero ou mais elementos da sequência original, sem alterar a ordem relativa dos elementos restantes. +A subsequência procurada deve ser um palíndromo, ou seja, deve ser idêntica quando lida de frente para trás ou de trás para frente. +O objetivo é identificar essa subsequência de tamanho máximo e apresentar tanto o seu comprimento quanto os próprios elementos. \ No newline at end of file diff --git a/longest-palindromic-subsequence/statement/input.tex b/longest-palindromic-subsequence/statement/input.tex new file mode 100644 index 0000000..30fd1c5 --- /dev/null +++ b/longest-palindromic-subsequence/statement/input.tex @@ -0,0 +1,3 @@ +A entrada é composta por duas linhas. +A primeira linha contém um inteiro \( n \) (\( 1 \leq n \leq 1000 \)), representando o número de caracteres da sequência. +A segunda linha contém uma string \( s \) de comprimento \( n \), composta por letras minúsculas do alfabeto. \ No newline at end of file diff --git a/longest-palindromic-subsequence/statement/notes.tex b/longest-palindromic-subsequence/statement/notes.tex new file mode 100644 index 0000000..1db1445 --- /dev/null +++ b/longest-palindromic-subsequence/statement/notes.tex @@ -0,0 +1,3 @@ +Para a sequência "bbbab", o tamanho da maior subsequência palindrômica é \( L = 4 \) e uma possível sequência é "bbbb". +Para a sequência "cbbd", a maior subsequência palindrômica é "bb", com tamanho \( L = 2 \). +Para a sequência "a", há apenas um elemento, então a maior subsequência palindrômica é o próprio caractere "a", com tamanho \( L = 1 \). \ No newline at end of file diff --git a/longest-palindromic-subsequence/statement/output.tex b/longest-palindromic-subsequence/statement/output.tex new file mode 100644 index 0000000..649d90a --- /dev/null +++ b/longest-palindromic-subsequence/statement/output.tex @@ -0,0 +1 @@ +A saída é composta por uma linha, um único inteiro, que representa representando o tamanho \( L \) da maior subsequência palindrômica. \ No newline at end of file diff --git a/longest-palindromic-subsequence/statement/preamble.tex b/longest-palindromic-subsequence/statement/preamble.tex new file mode 100644 index 0000000..e69de29 diff --git a/longest-palindromic-subsequence/statement/tutorial.tex b/longest-palindromic-subsequence/statement/tutorial.tex new file mode 100644 index 0000000..e69de29