Removed unrelated old stuff that is completely unrelated now
This commit is contained in:
parent
19f92d9207
commit
1328d194be
@ -1,68 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
@ -1,304 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
@ -1,287 +0,0 @@
|
||||
/* __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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user