From 6527ee98e06556e0d3051ffb4be53ea97291c465 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Mon, 20 Oct 2025 14:54:20 +0300 Subject: [PATCH] Funny tests (might remove later) --- CMakeLists.txt | 17 +- Makefile | 13 +- src/l1/anne/some_tests.h | 6 + src/l1/anne/util_temp_very_base.h | 2 +- src/l1/codegen/util_template_inst.h | 63 +++--- src/l1/core/util.h | 16 +- src/l1_5/core/input_olproga.h | 85 ++++++++ src/l1_5/core/stringsearch.h | 42 ++++ src/l2/margaret/vulkan_utils.h | 2 +- src/l2/tests/data_structures/t1.c | 93 +++++++++ src/l2/tests/r0/r0.c | 4 +- src/l2/tests/r_alg/H.c | 68 +++++++ src/l2/tests/r_alg/I.c | 304 ++++++++++++++++++++++++++++ src/l2/tests/r_alg/J.c | 287 ++++++++++++++++++++++++++ 14 files changed, 947 insertions(+), 55 deletions(-) create mode 100644 src/l1_5/core/input_olproga.h create mode 100644 src/l1_5/core/stringsearch.h create mode 100644 src/l2/tests/data_structures/t1.c create mode 100644 src/l2/tests/r_alg/H.c create mode 100644 src/l2/tests/r_alg/I.c create mode 100644 src/l2/tests/r_alg/J.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bbbc84..f5aee30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,11 +38,11 @@ add_compile_options(-fno-trapping-math) #add_executable(codegen_l1_5 src/l1_5/anne/codegen.c) -add_executable(0_render_test src/l2/tests/r0/r0.c gen/l_wl_protocols/xdg-shell-private.c) -target_link_libraries(0_render_test -lvulkan -lwayland-client -lm -lxkbcommon -lpng) +#add_executable(0_render_test src/l2/tests/r0/r0.c gen/l_wl_protocols/xdg-shell-private.c) +#target_link_libraries(0_render_test -lvulkan -lwayland-client -lm -lxkbcommon -lpng) -add_executable(0r_tex_init_prep src/l2/tests/r0/r0_tex_init_prep.c) -target_link_libraries(0r_tex_init_prep -lm -lpng) +#add_executable(0r_tex_init_prep src/l2/tests/r0/r0_tex_init_prep.c) +#target_link_libraries(0r_tex_init_prep -lm -lpng) #add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c) #target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon) @@ -57,4 +57,11 @@ target_link_libraries(0r_tex_init_prep -lm -lpng) #target_link_libraries(0_play_test -lncurses) # -#add_executable(l2t0 src/l2/tests/data_structures/t0.c) +add_compile_definitions(RUNNING_HERE) + +add_executable(l2t0 src/l2/tests/data_structures/t0.c) +add_executable(l2t1 src/l2/tests/data_structures/t1.c) +add_executable(H src/l2/tests/r_alg/H.c) +add_executable(I src/l2/tests/r_alg/I.c) +add_executable(J src/l2/tests/r_alg/J.c) + diff --git a/Makefile b/Makefile index c47440f..f32ad7a 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ HEADERS_src_l2 := $(HEADERS_gen_l1_5) $(call find_headers,l2) HEADERS_gen_l2 := $(HEADERS_src_l2) gen/l2/dorothy.txt cflags := -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type -Wno-unused-parameter \ - --std=c99 -g -ggdb -O3 \ + --std=c99 -g -ggdb -O0 \ -fno-trapping-math -D_POSIX_C_SOURCE=200112L -D_GNU_SOURCE cc := gcc @@ -106,7 +106,16 @@ out/l2/r3: src/l2/tests/r3/r3.c $(HEADERS_src_l2) $(l_wl_protocols) run_r3: out/l2/r3 ./out/l2/r3 +out/SICK_JOKE_H.c: src/l2/tests/r_alg/H.c $(HEADERS_gen_l1_5) + python src/l1/sobiralka.py $< $@ + +out/SICK_JOKE_I.c: src/l2/tests/r_alg/I.c $(HEADERS_gen_l1_5) + python src/l1/sobiralka.py $< $@ + +out/SICK_JOKE_J.c: src/l2/tests/r_alg/J.c $(HEADERS_gen_l1_5) + python src/l1/sobiralka.py $< $@ + .PHONY: clean clean: - rm -rf gen out + rm -rf gen out \ No newline at end of file diff --git a/src/l1/anne/some_tests.h b/src/l1/anne/some_tests.h index 22f5691..aa18468 100644 --- a/src/l1/anne/some_tests.h +++ b/src/l1/anne/some_tests.h @@ -32,6 +32,12 @@ void generate_headers_for_r0_r1_r2_r3() { .T = cstr("PlayingSound"), .vec_extended = true }); } + mkdir_nofail("l1/eve/r_alg"); + { /* r_alg. Wow! Even these freaks are here! */ + SpanU8 ns = cstr("r_alg"); + generate_eve_span_company_for_primitive(l, ns, cstr("I_FishNode"), true, false); + generate_eve_span_company_for_primitive(l, ns, cstr("J_AlphaVertex"), true, false); + } } #endif \ No newline at end of file diff --git a/src/l1/anne/util_temp_very_base.h b/src/l1/anne/util_temp_very_base.h index 13b4f47..ba32db6 100644 --- a/src/l1/anne/util_temp_very_base.h +++ b/src/l1/anne/util_temp_very_base.h @@ -6,7 +6,7 @@ /* These headers are guarded */ void generate_util_temp_very_base_headers() { SpanU8 l = cstr("l1"), ns = cstr(""); - SpanU8 T_codegen_VecAndSpan[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64")}; + SpanU8 T_codegen_VecAndSpan[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("S32"), cstr("U64"), cstr("S64")}; SpanU8 T_codegen_Option[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64")}; SpanU8 T_codegen_VecAndSpan_of_Vec[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64")}; SpanU8 T_codegen_VecAndSpan_of_Span[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64")}; diff --git a/src/l1/codegen/util_template_inst.h b/src/l1/codegen/util_template_inst.h index 00fa61b..25fabab 100644 --- a/src/l1/codegen/util_template_inst.h +++ b/src/l1/codegen/util_template_inst.h @@ -30,20 +30,20 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, VecU8_append_vec(&res, VecU8_fmt( "NODISCARD %s %s_new_reserved(size_t n) {\n" - SPACE "return (%s){ .buf = safe_calloc(n, sizeof(%s)), .len = 0, .capacity = n };\n" - "}\n\n", VecT, VecT, VecT, T)); + SPACE "return (%s){ .buf = (%s*)safe_calloc(n, sizeof(%s)), .len = 0, .capacity = n };\n" + "}\n\n", VecT, VecT, VecT, T, T)); VecU8_append_vec(&res, VecU8_fmt( - "void %s_append(%s* self, %s el) {\n" + "void %s_append(%s* self, %s el) {\n" /* VecT, VecT, T */ SPACE "size_t new_length = self->len + 1;\n" SPACE "if (new_length > self->capacity) {\n" SPACE SPACE "size_t new_capacity = Vec_get_new_capacity(self->capacity, new_length);\n" - SPACE SPACE "self->buf = safe_realloc(self->buf, new_capacity * sizeof(%s));\n" + SPACE SPACE "self->buf = (%s*)safe_realloc(self->buf, new_capacity * sizeof(%s));\n" /* T, T */ SPACE SPACE "self->capacity = new_capacity;\n" SPACE "}\n" SPACE "self->buf[self->len] = el;\n" SPACE "self->len = new_length;\n" - "}\n\n", VecT, VecT, T, T)); + "}\n\n", VecT, VecT, T, T, T)); VecU8_append_vec(&res, VecU8_fmt( "%s* %s_mat(%s* self, size_t i) {\n" @@ -59,9 +59,9 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, if (clonable) { VecU8_append_vec(&res, VecU8_fmt( - "NODISCARD %s %s_clone(const %s* self) {\n" - SPACE "%s res = (%s){.buf = safe_calloc(self->len, sizeof(%s)), .len = self->len, .capacity = self->len};\n", - VecT, VecT, VecT, VecT, VecT, T)); + "NODISCARD %s %s_clone(const %s* self) {\n" /* VecT, VecT, VecT */ + SPACE "%s res = (%s){.buf = (%s*)safe_calloc(self->len, sizeof(%s)), .len = self->len, .capacity = self->len};\n", + VecT, VecT, VecT, VecT, VecT, T, T)); if (primitive) { VecU8_append_vec(&res, VecU8_fmt(SPACE "memcpy(res.buf, self->buf, self->len * sizeof(%s));\n", T)); } else { @@ -73,11 +73,11 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, } VecU8_append_vec(&res, VecU8_fmt( - "void %s_append_vec(%s* self, %s b) {\n" + "void %s_append_vec(%s* self, %s b) {\n" /* VecT, VecT, VecT */ SPACE "size_t new_length = self->len + b.len;\n" SPACE "if (new_length > self->capacity) {\n" SPACE SPACE "size_t new_capacity = Vec_get_new_capacity(self->capacity, new_length);\n" - SPACE SPACE "self->buf = safe_realloc(self->buf, new_capacity * sizeof(%s));\n" + SPACE SPACE "self->buf = (%s*)safe_realloc(self->buf, new_capacity * sizeof(%s));\n" /* T, T */ SPACE SPACE "self->capacity = new_capacity;\n" SPACE "}\n" SPACE "for (size_t i = 0; i < b.len; i++){\n" @@ -85,13 +85,14 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive, SPACE "}\n" SPACE "self->len = new_length;\n" SPACE "free(b.buf);\n" - "}\n\n", VecT, VecT, VecT, T)); + "}\n\n", VecT, VecT, VecT, T, T)); if (primitive) { VecU8_append_vec(&res, VecU8_fmt( - "NODISCARD %s %s_new_zeroinit(size_t len) {\n" - SPACE "return (%s){.buf = safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" - "}\n\n", VecT, VecT, VecT, T)); + "NODISCARD %s %s_new_zeroinit(size_t len) {\n" /* VecT, VecT*/ + SPACE "return (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, T, T */ + "}\n\n", + VecT, VecT, VecT, T, T)); } VecU8_drop(g_VecT); // VecT invalidated too @@ -148,20 +149,20 @@ NODISCARD VecU8 generate_VecT_trivmove_extended_methods(SpanU8 T, bool primitive if (primitive) { VecU8_append_vec(&res, VecU8_fmt( - "NODISCARD %s %s_new_filled(size_t len, %s el) {\n" - SPACE "%s res = (%s){.buf = safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" + "NODISCARD %s %s_new_filled(size_t len, %s el) {\n" /* VecT, VecT, T */ + SPACE "%s res = (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, VecT, T, T */ SPACE "for (size_t i = 0; i < len; i++)\n" SPACE SPACE "res.buf[i] = el;\n" SPACE "return res;\n" - "}\n\n", VecT, VecT, T, VecT, VecT, T)); + "}\n\n", VecT, VecT, T, VecT, VecT, T, T)); } else if (clonable) { VecU8_append_vec(&res, VecU8_fmt( - "NODISCARD %s %s_new_filled(size_t len, const %s* el) {\n" - SPACE "%s res = (%s){.buf = safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" + "NODISCARD %s %s_new_filled(size_t len, const %s* el) {\n" /* VecT, VecT, T */ + SPACE "%s res = (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, VecT, T, T */ SPACE "for (size_t i = 0; i < len; i++)\n" - SPACE SPACE "res.buf[i] = %s_clone(el);\n" + SPACE SPACE "res.buf[i] = %s_clone(el);\n" /* T */ SPACE "return res;\n" - "}\n\n", VecT, VecT, T, VecT, VecT, T, T)); + "}\n\n", VecT, VecT, T, VecT, VecT, T, T, T)); } VecU8_drop(g_VecT); // VecT invalidated @@ -198,12 +199,12 @@ NODISCARD VecU8 generate_VecT_new_of_size_method(SpanU8 T) { VecU8 g_VecT = VecU8_fmt("Vec%s", T); SpanU8 VecT = VecU8_to_span(&g_VecT); VecU8 res = VecU8_fmt( - "NODISCARD %s %s_new_of_size(size_t len) {\n" - SPACE "%s res = (%s){.buf = safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" + "NODISCARD %s %s_new_of_size(size_t len) {\n" /* VecT, VecT */ + SPACE "%s res = (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, VecT, T, T */ SPACE "for (size_t i = 0; i < len; i++)\n" - SPACE SPACE "res.buf[i] = %s_new();\n" + SPACE SPACE "res.buf[i] = %s_new();\n" /* T */ SPACE "return res;\n" - "}\n", VecT, VecT, VecT, VecT, T, T); + "}\n", VecT, VecT, VecT, VecT, T, T, T); VecU8_drop(g_VecT); return res; @@ -319,9 +320,9 @@ NODISCARD VecU8 generate_SpanT_VecT_trivmove_collab(SpanU8 T, bool primitive, bo if (clonable) { VecU8_append_vec(&res, VecU8_fmt( - "NODISCARD %s %s_from_span(%s src){\n" - SPACE "%s res = (%s){ .buf = safe_calloc(src.len, sizeof(%s)), .len = src.len, .capacity = src.len };\n", - VecT, VecT, SpanT, VecT, VecT, T)); + "NODISCARD %s %s_from_span(%s src){\n" /* VecT, VecT, SpanT */ + SPACE "%s res = (%s){ .buf = (%s*)safe_calloc(src.len, sizeof(%s)), .len = src.len, .capacity = src.len };\n", /* VecT, VecT, T, T */ + VecT, VecT, SpanT, VecT, VecT, T, T)); if (primitive) { VecU8_append_vec(&res, VecU8_fmt( SPACE "memcpy(res.buf, src.data, src.len * sizeof(%s));\n", T)); @@ -346,13 +347,13 @@ NODISCARD VecU8 generate_SpanT_VecT_trivmove_collab(SpanU8 T, bool primitive, bo if (clonable) { VecU8_append_vec(&res, VecU8_fmt( - "void %s_append_span(%s* self, %s b) {\n" + "void %s_append_span(%s* self, %s b) {\n" /* VecT, VecT, SpanT */ SPACE "size_t new_length = self->len + b.len;\n" SPACE "if (new_length > self->capacity) {\n" SPACE SPACE "size_t new_capacity = Vec_get_new_capacity(self->capacity, new_length);\n" - SPACE SPACE "self->buf = safe_realloc(self->buf, new_capacity * sizeof(%s));\n" + SPACE SPACE "self->buf = (%s*)safe_realloc(self->buf, new_capacity * sizeof(%s));\n" /* T, T */ SPACE SPACE "self->capacity = new_capacity;\n" - SPACE "}\n", VecT, VecT, SpanT, T)); + SPACE "}\n", VecT, VecT, SpanT, T, T)); if (primitive) { VecU8_append_vec(&res, VecU8_fmt( SPACE "memcpy(self->buf + self->len, b.data, b.len * sizeof(%s));\n", T)); diff --git a/src/l1/core/util.h b/src/l1/core/util.h index 5011224..334d809 100644 --- a/src/l1/core/util.h +++ b/src/l1/core/util.h @@ -10,9 +10,9 @@ #include #include "int_primitives.h" -// Gonna change it when I face pedantic compilers -#define NORETURN [[noreturn]] -#define NODISCARD [[nodiscard]] +// Gonna change it +#define NORETURN __attribute((noreturn)) +#define NODISCARD __attribute((warn_unused_result)) typedef const char* CSTR; @@ -54,16 +54,6 @@ void* safe_realloc(void* ptr, size_t n) { return res; } -// todo: rewrite it to make it faster -#define unsigned_safe_mul_Definition(TSZ) \ -U##TSZ safe_mul_U##TSZ(U##TSZ a, U##TSZ b) { \ - if (b > 0 && a > UINT##TSZ##_MAX / b) \ - abortf("Overflow in multiplication: %" PRIu##TSZ " * %" PRIu##TSZ "\n", a, b); \ - return a * b; \ -} - -unsigned_safe_mul_Definition(64) - #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /* I assume that new_length > old_capacity */ diff --git a/src/l1_5/core/input_olproga.h b/src/l1_5/core/input_olproga.h new file mode 100644 index 0000000..433128c --- /dev/null +++ b/src/l1_5/core/input_olproga.h @@ -0,0 +1,85 @@ +#ifndef prototype1_src_l1_5_core_input_olproga_h +#define prototype1_src_l1_5_core_input_olproga_h + +#include "../../../gen/l1/OptionU64.h" +#include "../../../gen/l1/VecAndSpan_U8.h" + +void stdin_skip_whitespaces(){ + while (true) { + int ch = fgetc(stdin); + if (ch == EOF) + return; + if (ch < 0) { + perror("fgetc(stdin)"); + abort(); + } + if (ch != ' ' && ch != '\t' && ch != '\n') { + ungetc(ch, stdin); + break; + } + } +} + +// Aborts on error +OptionU64 stdin_read_U64(){ + stdin_skip_whitespaces(); + U64 x = 0; + int i = 0; + for (;; i++) { + int ch = fgetc(stdin); + if (ch == EOF) + break; + if (ch < 0) { + perror("fgetc(stdin)"); + abort(); + } + if (!('0' <= ch && ch <= '9')) { + ungetc(ch, stdin); + break; + } + U64 d = (U64)(ch - '0'); + if (x == 0 && i > 0) + abortf("Bad integer input\n"); + if (x > UINT64_MAX / 10) + abortf("Integer input exceeds UINT64_MAX\n"); + x *= 10; + if (x > UINT64_MAX - d) + abortf("Integer input exceeds UINT64_MAX\n"); + x += d; + } + if (i > 0) + return Some_U64(x); + return None_U64(); +} + +/* If empty string is returned it means EOF was reached */ +NODISCARD VecU8 stdin_read_VecU8_nospace(){ + stdin_skip_whitespaces(); + VecU8 str = VecU8_new(); + while (true) { + int ch = fgetc(stdin); + if (ch == EOF) + break; + if (ch < 0) { + perror("fgetc(stdin)"); + abort(); + } + if (ch == ' ' || ch == '\t' || ch == '\n') { + ungetc(ch, stdin); + break; + } + VecU8_append(&str, ch); + } + return str; +} + +// Aborts if non-integer input or EOF was encountered before my integer +U64 stdin_read_U64_nofail(){ + OptionU64 x = stdin_read_U64(); + if (x.variant == Option_None) + abortf("No number found\n"); + return x.some; +} + + +#endif \ No newline at end of file diff --git a/src/l1_5/core/stringsearch.h b/src/l1_5/core/stringsearch.h new file mode 100644 index 0000000..8889dfd --- /dev/null +++ b/src/l1_5/core/stringsearch.h @@ -0,0 +1,42 @@ +#ifndef prototype1_src_l1_5_core_stringsearch_h +#define prototype1_src_l1_5_core_stringsearch_h + +#include "../../l1/core/VecU8_as_str.h" +#include "../../../gen/l1/VecAndSpan_U64.h" + +NODISCARD VecU64 prefix_function(SpanU8 s){ + VecU64 prefix = VecU64_new_zeroinit(s.len + 1); + for (size_t i = 1; i < s.len; i++) { + size_t k = prefix.buf[i]; + while (k > 0 && s.data[k] != s.data[i]) + k = prefix.buf[k]; + if (s.data[k] == s.data[i]) + k++; + prefix.buf[i + 1] = k; + } + return prefix; +} + + +NODISCARD VecU64 z_function(SpanU8 s){ + VecU64 Z = VecU64_new_zeroinit(s.len + 1); + Z.buf[0] = s.len; + size_t l = 0, r = 0; + for (size_t i = 1; i <= s.len; i++) { + if (i + 1 < r) { + Z.buf[i] = MIN_U64(r - i, Z.buf[i - l]); + } + while (i + Z.buf[i] < s.len && s.data[Z.buf[i]] == s.data[i + Z.buf[i]]) { + Z.buf[i]++; + } + if (i + Z.buf[i] >= r) { + l = i; + r = i + Z.buf[i]; + } + } + return Z; +} + + +#endif + diff --git a/src/l2/margaret/vulkan_utils.h b/src/l2/margaret/vulkan_utils.h index b61c2df..13fa242 100644 --- a/src/l2/margaret/vulkan_utils.h +++ b/src/l2/margaret/vulkan_utils.h @@ -1007,7 +1007,7 @@ VkDeviceMemory margaret_initialize_buffers_and_images( #define margaret_prep_buffer_mem_info_of_gpu_vbo_Definition(TV) \ MargaretBufferInMemoryInfo TV##_buffer_crinfo_of_gpu_vbo(size_t n) { \ return (MargaretBufferInMemoryInfo){ \ - .sz = safe_mul_U64(sizeof(TV), n), \ + .sz = sizeof(TV) * n, \ .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT \ }; \ } diff --git a/src/l2/tests/data_structures/t1.c b/src/l2/tests/data_structures/t1.c new file mode 100644 index 0000000..9c656b7 --- /dev/null +++ b/src/l2/tests/data_structures/t1.c @@ -0,0 +1,93 @@ +#include "../../../l1_5/core/stringsearch.h" + +void VecU64_fprint_debug_vivod(FILE* file, const VecU64* vec){ + for (size_t i = 0; i < vec->len; i++) { + fprintf(file, "%lu ", vec->buf[i]); + } + fprintf(file, "\n"); +} + +VecU64 trivial_prefix_function(SpanU8 s){ + VecU64 prefix = VecU64_new_zeroinit(s.len + 1); + for (size_t i = 0; i <= s.len; i++) { + for (size_t k = 0; k < i; k++) { + for (size_t j = 0; j < k; j++) { + if (s.data[j] != s.data[i - k + j]) + goto cnt; + } + prefix.buf[i] = k; + cnt: + continue; + } + } + return prefix; +} + +VecU64 trivial_z_function(SpanU8 s){ + VecU64 z = VecU64_new_zeroinit(s.len + 1); + for (size_t i = 0; i <= s.len; i++) { + for (size_t j = 0; i + j < s.len; j++) { + if (s.data[j] != s.data[i + j]) + break; + z.buf[i]++; + } + } + return z; +} + +void test_prefix_function(SpanU8 str){ + VecU64 correct = trivial_prefix_function(str); + VecU64 my = prefix_function(str); + if (!VecU64_equal_VecU64(&correct, &my)) { + fprintf(stderr, "Test Pi "); + SpanU8_fprint(str, stderr); + fprintf(stderr, "\n"); + fprintf(stderr, "Correct: "); + VecU64_fprint_debug_vivod(stderr, &correct); + fprintf(stderr, "My: "); + VecU64_fprint_debug_vivod(stderr, &my); + abort(); + } + VecU64_drop(correct); + VecU64_drop(my); +} + +void test_z_function(SpanU8 str){ + VecU64 correct = trivial_z_function(str); + VecU64 my = z_function(str); + if (!VecU64_equal_VecU64(&correct, &my)) { + fprintf(stderr, "Test Z "); + SpanU8_fprint(str, stderr); + fprintf(stderr, "\n"); + fprintf(stderr, "Correct: "); + VecU64_fprint_debug_vivod(stderr, &correct); + fprintf(stderr, "My: "); + VecU64_fprint_debug_vivod(stderr, &my); + abort(); + } + VecU64_drop(correct); + VecU64_drop(my); +} + +int main(){ + test_prefix_function(cstr("")); + test_prefix_function(cstr("a")); + test_prefix_function(cstr("ab")); + test_prefix_function(cstr("aaaa")); + test_prefix_function(cstr("aabbaabxxxaabbaab")); + + test_z_function(cstr("")); + test_z_function(cstr("a")); + test_z_function(cstr("aa")); + test_z_function(cstr("aaa")); + test_z_function(cstr("aaaa")); + test_z_function(cstr("ab")); + test_z_function(cstr("aba")); + test_z_function(cstr("bbaa")); + test_z_function(cstr("abacad")); + + test_prefix_function(cstr("hsooihoioifodoiwoihoiodisifoioihhhshshsshsoodfojoioow")); + test_z_function(cstr("kdfkjpkjpksdpsdkpfpkspksfpksdpjpsdpdfjpospsdjpsdpfpspsf")); + test_prefix_function(cstr("alkalaalkalakalkalakklakalalkalaakllaklakka")); + test_z_function(cstr("alkalaalkalakalkalakklakalalkalaakllaklakka")); +} diff --git a/src/l2/tests/r0/r0.c b/src/l2/tests/r0/r0.c index b7ddd8f..afaf04b 100644 --- a/src/l2/tests/r0/r0.c +++ b/src/l2/tests/r0/r0.c @@ -98,11 +98,11 @@ VkRenderPass create_render_pass_0(VkDevice logical_device, VkFormat colorbuffer_ } MargaretBufferInMemoryInfo GenericMeshVertex_buffer_crinfo_of_gpu_vbo(size_t n) { - return (MargaretBufferInMemoryInfo){ .sz = safe_mul_U64(sizeof(GenericMeshVertex), n), + return (MargaretBufferInMemoryInfo){ .sz = sizeof(GenericMeshVertex) * n, .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT }; } MargaretBufferInMemoryInfo ShinyMeshVertex_buffer_crinfo_of_gpu_vbo(size_t n) { - return (MargaretBufferInMemoryInfo){ .sz = safe_mul_U64(sizeof(ShinyMeshVertex), n), + return (MargaretBufferInMemoryInfo){ .sz = sizeof(ShinyMeshVertex) * n, .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT }; } diff --git a/src/l2/tests/r_alg/H.c b/src/l2/tests/r_alg/H.c new file mode 100644 index 0000000..befa95a --- /dev/null +++ b/src/l2/tests/r_alg/H.c @@ -0,0 +1,68 @@ +/* We switch on the light */ + +#include "../../../l1_5/core/stringsearch.h" +#include "../../../l1_5/core/input_olproga.h" +#include "../../../../gen/l1/VecAndSpan_VecU64.h" +#include "../../../../gen/l1/VecAndSpan_U64.h" + +// Aborts on errors + +U64 fast_solution(U64 n, U64 a, U64 b, const VecU8* S){ + VecVecU64 Z = VecVecU64_new(); + for (size_t i = 0; i < n; i++) { + VecU64 z = z_function(VecU8_span(S, i, n - i)); + VecVecU64_append(&Z, z); + } + VecU64 dp = VecU64_new_filled(n + 1, UINT64_MAX); + dp.buf[0] = 0; + + for (size_t k = 0; k < n; k++) { + size_t score_here = dp.buf[k]; + dp.buf[k + 1] = MIN_U64(dp.buf[k + 1], score_here + a); + size_t lets = 0; + for (size_t sss = 0; sss <= k; sss++) { + size_t before = k - sss; + size_t reach = Z.buf[sss].buf[before]; + lets = MAX_U64(lets, MIN_U64(reach, before)); + } + for (size_t after = 1; after <= lets; after++) { + dp.buf[k + after] = MIN_U64(dp.buf[k + after], score_here + b); + } + } + return dp.buf[n]; +} + +U64 correct_solution(U64 n, U64 a, U64 b, const VecU8* S){ + VecU64 dp = VecU64_new_filled(n + 1, UINT64_MAX); + dp.buf[0] = 0; + + for (size_t i = 1; i <= n; i++) { + dp.buf[i] = dp.buf[i - 1] + a; + for (size_t gb = 1; gb <= i; gb++) { + for (size_t start = 0; start + gb * 2 <= i; gb++) { + for (size_t j = 0; j < gb; j++) { + if (S->buf[start + j] != S->buf[i - gb + j]) + goto incorrect; + } + /* It was correct */ + dp.buf[i] = MIN_U64(dp.buf[i], dp.buf[i - gb] + b); + incorrect: + continue; + } + } + } + return dp.buf[n]; +} + +int main(){ + U64 n = stdin_read_U64_nofail(); + U64 a = stdin_read_U64_nofail(); + U64 b = stdin_read_U64_nofail(); + VecU8 S = stdin_read_VecU8_nospace(); + assert(n != 0 && S.len == n); + assert(n <= 5000); + assert(a <= 5000 && b <= 5000); + + printf("%lu\n", fast_solution(n, a, b, &S)); + return 0; +} diff --git a/src/l2/tests/r_alg/I.c b/src/l2/tests/r_alg/I.c new file mode 100644 index 0000000..ff36bbd --- /dev/null +++ b/src/l2/tests/r_alg/I.c @@ -0,0 +1,304 @@ +/* Your death is near */ + +#include "../../../../gen/l1/VecAndSpan_U8.h" +#include "../../../../gen/l1/VecAndSpan_VecU8.h" +#include "../../../../gen/l1/VecAndSpan_VecU32.h" +#include "../../../../gen/l1/VecAndSpan_S64.h" +#include "../../../../gen/l1/VecAndSpan_U64.h" +// #include "../../../l1_5/core/input_olproga.h" +#include "../../../../gen/l1/OptionU64.h" + +#define BUF_SIZE 4096 +static unsigned char buf[BUF_SIZE]; +static size_t pos = 0, sz = 0; +static int pushback = EOF; + +int fast_getc() { + if (pushback != EOF) { + int c = pushback; + pushback = EOF; + return c; + } + if (pos == sz) { + sz = fread(buf, 1, BUF_SIZE, stdin); + pos = 0; + if (sz == 0) return EOF; + } + return (int)buf[pos++]; +} + +void fast_ungetc(int c) { + if (pushback != EOF) { + abort(); // Multiple pushbacks not supported (not needed in your functions) + } + pushback = c; +} + +void stdin_skip_whitespaces() { + while (true) { + int ch = fast_getc(); + if (ch == EOF) + return; + if (ch != ' ' && ch != '\t' && ch != '\n') { + fast_ungetc(ch); + break; + } + } +} + +// Aborts on error +OptionU64 stdin_read_U64() { + stdin_skip_whitespaces(); + U64 x = 0; + int i = 0; + for (;; i++) { + int ch = fast_getc(); + if (ch == EOF) + break; + if (!('0' <= ch && ch <= '9')) { + fast_ungetc(ch); + break; + } + U64 d = (U64)(ch - '0'); + if (x == 0 && i > 0) + abortf("Bad integer input\n"); + if (x > UINT64_MAX / 10) + abortf("Integer input exceeds UINT64_MAX\n"); + x *= 10; + if (x > UINT64_MAX - d) + abortf("Integer input exceeds UINT64_MAX\n"); + x += d; + } + if (i > 0) + return Some_U64(x); + return None_U64(); +} + +/* If empty string is returned it means EOF was reached */ +NODISCARD VecU8 stdin_read_VecU8_nospace() { + stdin_skip_whitespaces(); + VecU8 str = VecU8_new(); + while (true) { + int ch = fast_getc(); + if (ch == EOF) + break; + if (ch == ' ' || ch == '\t' || ch == '\n') { + fast_ungetc(ch); + break; + } + VecU8_append(&str, ch); + } + return str; +} + +// Aborts if non-integer input or EOF was encountered before my integer +U64 stdin_read_U64_nofail() { + OptionU64 x = stdin_read_U64(); + if (x.variant == Option_None) + abortf("No number found\n"); + return x.some; +} + + +typedef struct { + U64 suf_link; + U64 ans_up_link; + U64 transition[26]; + S64 class_ref; +} I_FishNode; + +I_FishNode I_FishNode_new(){ + /* C++ is fucking lame*/ + return (I_FishNode){.suf_link = 0, .ans_up_link = 0, .transition = {0}, .class_ref = -1}; + // return (I_FishNode){.class_ref = -1}; +} + +#include "../../../../gen/l1/eve/r_alg/VecI_FishNode.h" + +typedef struct { + VecS64 next_same_ref_on_strings; + VecI_FishNode nodes; +} Fish; + +Fish incomplete_Fish_from_VecU8(SpanVecU8 S){ + VecS64 next_same_ref_on_strings = VecS64_new_filled(S.len, -1); + VecI_FishNode nodes = VecI_FishNode_new_reserved(1000001); + VecI_FishNode_append(&nodes, I_FishNode_new()); + assert(nodes.buf[0].suf_link == 0 && nodes.buf[0].ans_up_link == 0 && nodes.buf[0].transition[0] == 0); + for (size_t j = 0; j < S.len; j++) { + SpanU8 str = VecU8_to_span(&S.data[j]); + U64 cur = 0; /* cur trie node */ + for (size_t i = 0; i < str.len; i++) { + U8 ch = str.data[i]; + assert('a' <= ch && ch <= 'z'); + U8 d = ch - 'a'; + assert(d < 26); + assert(cur < nodes.len); + if (nodes.buf[cur].transition[d] == 0) { + U64 nid = nodes.len; + VecI_FishNode_append(&nodes, I_FishNode_new()); + nodes.buf[cur].transition[d] = nid; + } + assert(nodes.buf[cur].transition[d] < nodes.len); + assert(nodes.buf[cur].transition[d] != 0); + cur = nodes.buf[cur].transition[d]; + } + if (nodes.buf[cur].class_ref != -1) { + assert(next_same_ref_on_strings.buf[j] == -1); + next_same_ref_on_strings.buf[j] = nodes.buf[cur].class_ref; + } + nodes.buf[cur].class_ref = (S64)j; + } + return (Fish){.next_same_ref_on_strings=next_same_ref_on_strings, .nodes=nodes}; +} + +/* Debug function */ +void Fish_debug_print(const Fish* self){ + printf("next_same_ref_on_strings:\n"); + for (size_t i = 0; i < self->next_same_ref_on_strings.len; i++) + printf("%3ld ", self->next_same_ref_on_strings.buf[i]); + printf("\n"); + size_t nc = self->nodes.len; + for (size_t i = 0; i < nc; i++) + printf("=== "); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("%3ld ", self->nodes.buf[i].class_ref); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("--- "); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("%3lu ", self->nodes.buf[i].suf_link); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("--- "); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("%3lu ", self->nodes.buf[i].ans_up_link); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("--- "); + printf("\n"); + for (U8 d = 0; d < 26; d++) { + for (size_t i = 0; i < nc; i++) { + printf("%3lu ", self->nodes.buf[i].transition[d]); + } + printf("\n"); + } +} + +void complete_Fish(Fish* fish){ + /* trie unpacked */ + size_t nc = fish->nodes.len; + assert(nc >= 1); + /* We first, fields suf_link, ans_up_link are filled with garbage */ + // Except for root. Root is already almost initialized + assert(fish->nodes.buf[0].suf_link == 0 && fish->nodes.buf[0].ans_up_link == 0); + // Some transitions are already complete. Those that contain 0 are yet to be filled + // transitions to 0 can't occur naturally in Trie. (Incomplete Fish = Trie) + + VecU64 bfs_cur = VecU64_new_zeroinit(1); /* Initialize with one node pointing to the */ + VecU64 bfs_next = VecU64_new(); + while (bfs_cur.len > 0) { + do { + U64 pu = VecU64_pop(&bfs_cur); + for (U8 d = 0; d < 26; d++) { + if (fish->nodes.buf[pu].transition[d] != 0) { + U64 u = fish->nodes.buf[pu].transition[d]; + U64 u_suf_link = pu == 0 ? 0 : fish->nodes.buf[fish->nodes.buf[pu].suf_link].transition[d]; + fish->nodes.buf[u].suf_link = u_suf_link; + + if (fish->nodes.buf[u_suf_link].class_ref != -1) { + fish->nodes.buf[u].ans_up_link = u_suf_link; + } else { + fish->nodes.buf[u].ans_up_link = fish->nodes.buf[u_suf_link].ans_up_link; + } + + // fish->nodes.buf[pu].transition[d] = u; + VecU64_append(&bfs_next, u); + } else if (pu == 0) { + fish->nodes.buf[pu].transition[d] = 0; + } else { + fish->nodes.buf[pu].transition[d] = fish->nodes.buf[fish->nodes.buf[pu].suf_link].transition[d]; + } + } + } while (bfs_cur.len > 0); + VecU64 t = bfs_cur; + bfs_cur = bfs_next; + bfs_next = t; + } + VecU64_drop(bfs_cur); + VecU64_drop(bfs_next); +} + +void Fish_drop(Fish self){ + VecS64_drop(self.next_same_ref_on_strings); + VecI_FishNode_drop(self.nodes); +} + +int main() { + // #ifndef RUNNING_HERE + freopen("inputik.txt", "r", stdin); + freopen("outputik.txt", "w", stdout); + // #endif + + VecU8 T = stdin_read_VecU8_nospace(); + U64 N = stdin_read_U64_nofail(); + VecVecU8 S = VecVecU8_new_of_size(N); + for (size_t i = 0; i < N; i++) { + VecU8 s = stdin_read_VecU8_nospace(); + assert(S.buf[i].buf == NULL); + S.buf[i] = s; + } + Fish fish = incomplete_Fish_from_VecU8(VecVecU8_to_span(&S)); + // Fish_debug_print(&fish); + complete_Fish(&fish); + + VecVecU32 answer = VecVecU32_new_of_size(N); + /* going through T to fill answer */ + U64 fish_v = 0; + for (size_t i = 0;; i++) { + int VIBE_CHECK = 0; // Can be safely removed + U64 CUR = fish_v; + while (true) { + S64 j_in_class = fish.nodes.buf[CUR].class_ref; + if (j_in_class == -1) // Can be safely removed + VIBE_CHECK++; // Can be safely removed + while (j_in_class != -1) { + assert(j_in_class < (S64)N); + size_t slen = S.buf[j_in_class].len; + assert(slen <= i); + VecU32_append(&answer.buf[j_in_class], (U32)(i - slen)); + j_in_class = fish.next_same_ref_on_strings.buf[j_in_class]; + } + /* We give a root a chance to execute, yet this is where we stop */ + if (CUR == 0) + break; + CUR = fish.nodes.buf[CUR].ans_up_link; + } + if (VIBE_CHECK > 2) // Can be safely removed + abort(); // Can be safely removed + + if (i == T.len) + break; + + U8 ch = T.buf[i]; + assert('a' <= ch && ch <= 'z'); + U8 d = ch - 'a'; + assert(d < 26); + fish_v = fish.nodes.buf[fish_v].transition[d]; + } + for (size_t i = 0; i < N; i++) { + printf("%lu", answer.buf[i].len); + for (size_t e = 0; e < answer.buf[i].len; e++) { + printf(" %u", answer.buf[i].buf[e] + 1); + } + printf("\n"); + } + VecVecU8_drop(S); + VecVecU32_drop(answer); + Fish_drop(fish); + VecU8_drop(T); + return 0; +} \ No newline at end of file diff --git a/src/l2/tests/r_alg/J.c b/src/l2/tests/r_alg/J.c new file mode 100644 index 0000000..d0bd56a --- /dev/null +++ b/src/l2/tests/r_alg/J.c @@ -0,0 +1,287 @@ +/* __You get millions of volts__ */ + +#include "../../../../gen/l1/VecAndSpan_U8.h" +#include "../../../../gen/l1/VecAndSpan_VecU8.h" +#include "../../../../gen/l1/VecAndSpan_S64.h" +#include "../../../../gen/l1/VecAndSpan_U64.h" +#include "../../../l1_5/core/input_olproga.h" + +typedef struct { + U64 suf_link; + U64 ans_up_link; + U64 transition[26]; + S64 class_ref; +} I_FishNode; + +I_FishNode I_FishNode_new(){ + /* C++ is fucking lame*/ + return (I_FishNode){.suf_link = 0, .ans_up_link = 0, .transition = {0}, .class_ref = -1}; + // return (I_FishNode){.class_ref = -1}; +} + +#include "../../../../gen/l1/eve/r_alg/VecI_FishNode.h" + +typedef struct { + VecS64 next_same_ref_on_strings; + VecI_FishNode nodes; +} Fish; + +Fish incomplete_Fish_from_VecU8(SpanVecU8 S){ + VecS64 next_same_ref_on_strings = VecS64_new_filled(S.len, -1); + VecI_FishNode nodes = VecI_FishNode_new_reserved(1000001); + VecI_FishNode_append(&nodes, I_FishNode_new()); + assert(nodes.buf[0].suf_link == 0 && nodes.buf[0].ans_up_link == 0 && nodes.buf[0].transition[0] == 0); + for (size_t j = 0; j < S.len; j++) { + SpanU8 str = VecU8_to_span(&S.data[j]); + U64 cur = 0; /* cur trie node */ + for (size_t i = 0; i < str.len; i++) { + U8 ch = str.data[i]; + assert('a' <= ch && ch <= 'z'); + U8 d = ch - 'a'; + assert(d < 26); + assert(cur < nodes.len); + if (nodes.buf[cur].transition[d] == 0) { + U64 nid = nodes.len; + VecI_FishNode_append(&nodes, I_FishNode_new()); + nodes.buf[cur].transition[d] = nid; + } + assert(nodes.buf[cur].transition[d] < nodes.len); + assert(nodes.buf[cur].transition[d] != 0); + cur = nodes.buf[cur].transition[d]; + } + if (nodes.buf[cur].class_ref != -1) { + assert(next_same_ref_on_strings.buf[j] == -1); + next_same_ref_on_strings.buf[j] = nodes.buf[cur].class_ref; + } + nodes.buf[cur].class_ref = (S64)j; + } + return (Fish){.next_same_ref_on_strings=next_same_ref_on_strings, .nodes=nodes}; +} + +/* Debug function */ +void Fish_debug_print(const Fish* self){ + printf("next_same_ref_on_strings:\n"); + for (size_t i = 0; i < self->next_same_ref_on_strings.len; i++) + printf("%3ld ", self->next_same_ref_on_strings.buf[i]); + printf("\n"); + size_t nc = self->nodes.len; + for (size_t i = 0; i < nc; i++) + printf("=== "); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("%3ld ", self->nodes.buf[i].class_ref); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("--- "); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("%3lu ", self->nodes.buf[i].suf_link); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("--- "); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("%3lu ", self->nodes.buf[i].ans_up_link); + printf("\n"); + for (size_t i = 0; i < nc; i++) + printf("--- "); + printf("\n"); + for (U8 d = 0; d < 26; d++) { + for (size_t i = 0; i < nc; i++) { + printf("%3lu ", self->nodes.buf[i].transition[d]); + } + printf("\n"); + } +} + +void complete_Fish(Fish* fish){ + /* trie unpacked */ + size_t nc = fish->nodes.len; + assert(nc >= 1); + /* We first, fields suf_link, ans_up_link are filled with garbage */ + // Except for root. Root is already almost initialized + assert(fish->nodes.buf[0].suf_link == 0 && fish->nodes.buf[0].ans_up_link == 0); + // Some transitions are already complete. Those that contain 0 are yet to be filled + // transitions to 0 can't occur naturally in Trie. (Incomplete Fish = Trie) + + VecU64 bfs_cur = VecU64_new_zeroinit(1); /* Initialize with one node pointing to the */ + VecU64 bfs_next = VecU64_new(); + while (bfs_cur.len > 0) { + do { + U64 pu = VecU64_pop(&bfs_cur); + for (U8 d = 0; d < 26; d++) { + if (fish->nodes.buf[pu].transition[d] != 0) { + U64 u = fish->nodes.buf[pu].transition[d]; + U64 u_suf_link = pu == 0 ? 0 : fish->nodes.buf[fish->nodes.buf[pu].suf_link].transition[d]; + fish->nodes.buf[u].suf_link = u_suf_link; + + if (fish->nodes.buf[u_suf_link].class_ref != -1) { + fish->nodes.buf[u].ans_up_link = u_suf_link; + } else { + fish->nodes.buf[u].ans_up_link = fish->nodes.buf[u_suf_link].ans_up_link; + } + + // fish->nodes.buf[pu].transition[d] = u; + VecU64_append(&bfs_next, u); + } else if (pu == 0) { + fish->nodes.buf[pu].transition[d] = 0; + } else { + fish->nodes.buf[pu].transition[d] = fish->nodes.buf[fish->nodes.buf[pu].suf_link].transition[d]; + } + } + } while (bfs_cur.len > 0); + VecU64 t = bfs_cur; + bfs_cur = bfs_next; + bfs_next = t; + } + VecU64_drop(bfs_cur); + VecU64_drop(bfs_next); +} + +void Fish_drop(Fish self){ + VecS64_drop(self.next_same_ref_on_strings); + VecI_FishNode_drop(self.nodes); +} + +typedef struct { + U64 trans[26]; +} J_AlphaVertex; + +#include "../../../../gen/l1/eve/r_alg/VecJ_AlphaVertex.h" + +typedef struct{ + size_t only_trash_state; + size_t start; + VecJ_AlphaVertex states; +} AntiGraph; + +void AntiGraph_drop(AntiGraph self){ + VecJ_AlphaVertex_drop(self.states); +} + +U64 Fish_anti_automaton_dfs(U64 fv, VecS64* map, VecJ_AlphaVertex* graph, const VecI_FishNode* fish){ + assert(fv < map->len); + assert(fv < fish->len); + /* Priority number 1: check if it is terminal */ + if (fish->buf[fv].class_ref != -1 || fish->buf[fish->buf[fv].ans_up_link].class_ref != -1) + return 0; // Trash vertex + if (map->buf[fv] == -1) { + size_t mid = graph->len; + map->buf[fv] = (S64)mid; + /* Right now it is filled with trash. The important point is that it marked as visited */ + VecJ_AlphaVertex_append(graph, (J_AlphaVertex){0}); + for (U8 d = 0; d < 26; d++) { + U64 nnon = Fish_anti_automaton_dfs(fish->buf[fv].transition[d], map, graph, fish); + graph->buf[mid].trans[d] = nnon; + } + } + return map->buf[fv]; +} + +AntiGraph Fish_anti_automaton(Fish fish){ + size_t nc = fish.nodes.len; + assert(nc > 0); + /* starting with just trash vertex, it ppints to inself, zalooping on itself */ + VecJ_AlphaVertex graph = VecJ_AlphaVertex_new_zeroinit(1); + VecS64 map = VecS64_new_filled(nc, -1); + U64 start = Fish_anti_automaton_dfs(0, &map, &graph, &fish.nodes); + + Fish_drop(fish); + VecS64_drop(map); + return (AntiGraph){.only_trash_state = 0, .start = start, .states = graph}; +} + +#define MOD (1000000007) + +NODISCARD VecU64 mat_mul(uint32_t N, const VecU64* A, const VecU64* B){ + assert(A->len == N * N && B->len == N * N); + VecU64 C = VecU64_new_zeroinit(N * N); + for (size_t y = 0; y < N; y++) { + for (size_t x = 0; x < N; x++) { + size_t s = 0; + for (size_t k = 0; k < N; k++) { + s = (s + (A->buf[y * N + k] * B->buf[k * N + x]) % MOD) % MOD; + } + C.buf[y * N + x] = s; + } + } + return C; +} + +NODISCARD VecU64 pow_matrix(uint32_t N, const VecU64* A, uint64_t B){ + if (B == 0) { + VecU64 E = VecU64_new_zeroinit(N * N); + for (size_t k = 0; k < N; k++) + E.buf[N * k + k] = 1; + return E; + } + if (B == 1) + return VecU64_clone(A); + uint64_t b = B / 2; + VecU64 e = pow_matrix(N, A, b); + assert(e.len == N * N); + VecU64 E = mat_mul(N, &e, &e); + VecU64_drop(e); // e is no more + if (B % 2 == 0) + return E; + VecU64 F = mat_mul(N, &E, A); + VecU64_drop(E); + return F; +} + +void VecU64_debug_print_cool_matrix(size_t N, const VecU64* matrix){ + assert(matrix->len == N * N); + for (size_t y = 0; y < N; y++) { + for (size_t x = 0; x < N; x++) + printf(" %2lu", matrix->buf[y * N + x]); + printf("\n"); + } +} + + +int main(){ + U64 K = stdin_read_U64_nofail(); + U64 m = stdin_read_U64_nofail(); + VecVecU8 S = VecVecU8_new_of_size(m); + for (size_t i = 0; i < m; i++) { + U64 sn = stdin_read_U64_nofail(); + if (sn == 0) + abort(); + assert(S.buf[i].buf == NULL); + S.buf[i] = stdin_read_VecU8_nospace(); + // assert(S.buf[i].len == sn); + } + // I_Trie_debug_print(&trie); + Fish fish = incomplete_Fish_from_VecU8(VecVecU8_to_span(&S)); + complete_Fish(&fish); + // Fish_debug_print(&fish); + AntiGraph antigraph = Fish_anti_automaton(fish); + size_t N = antigraph.states.len; + assert(1 < N); + assert(0 == antigraph.only_trash_state); + VecU64 graph_matrix = VecU64_new_zeroinit(N * N); + + for (size_t v = 0; v < N; v++) { + for (U8 d = 0; d < 26; d++) { + size_t t = antigraph.states.buf[v].trans[d]; + assert(t < N); + graph_matrix.buf[t * N + v]++; + } + } + + // VecU64_debug_print_cool_matrix(N, &graph_matrix); + + VecU64 K_graph_matrix = pow_matrix(N, &graph_matrix, K); + + U64 K_paths = 0; + for (size_t endpoint = 1; endpoint < N; endpoint++) { + K_paths = (K_paths + K_graph_matrix.buf[endpoint * N + antigraph.start]) % MOD; + } + + printf("%lu\n", K_paths); + + VecU64_drop(graph_matrix); + VecU64_drop(K_graph_matrix); + AntiGraph_drop(antigraph); + VecVecU8_drop(S); +}