size_t[string][string] memoAAs;
string[] targetInfixes;
size_t[string] count(const string from) @safe {
size_t[string] aa;
if (from in memoAAs) {
return memoAAs[from];
} else if (from.length <= 1) {
foreach (inf; targetInfixes)
aa[inf] = 0;
aa[""] = 1;
aa[from] = 1;
} else {
const auto f = count(from[0..($/2)]);
const auto l = count(from[($/2)..$]);
foreach (inf; targetInfixes) {
aa[inf] = 0;
for (size_t i = 0; i <= inf.length; ++i) {
aa[inf] += f[inf[0..i]] * l[inf[i..$]];
}
}
}
memoAAs[from] = aa;
return aa;
}
string[] infixes(string s) @safe {
import std.array;
auto a = appender!(string[]);
size_t i = 0;
size_t e = 0;
while (i != s.length) {
a.put(s[i..e]);
if (e == s.length){
++i; e = i + 1;
} else {
++e;
}
}
return a.data;
}
void main() @safe {
import std.stdio : writeln;
import std.utf : toUTF8;
import std.range : join, repeat;
auto odai = "odai";
auto ss = [ "odadai", "odaiodai", "ooooddddaaaaiiii", "daioadiao" ];
targetInfixes = infixes(odai);
foreach (s; ss) {
string t = s.repeat(1000).join.toUTF8;
writeln(count(t)[odai]);
}
}
CnNpemVfdFtzdHJpbmddW3N0cmluZ10gbWVtb0FBczsKc3RyaW5nW10gdGFyZ2V0SW5maXhlczsKCnNpemVfdFtzdHJpbmddIGNvdW50KGNvbnN0IHN0cmluZyBmcm9tKSBAc2FmZSB7CiAgICBzaXplX3Rbc3RyaW5nXSBhYTsKICAgIGlmIChmcm9tIGluIG1lbW9BQXMpIHsKICAgICAgICByZXR1cm4gbWVtb0FBc1tmcm9tXTsKICAgIH0gZWxzZSBpZiAoZnJvbS5sZW5ndGggPD0gMSkgewogICAgICAgIGZvcmVhY2ggKGluZjsgdGFyZ2V0SW5maXhlcykKICAgICAgICAgICAgYWFbaW5mXSA9IDA7CiAgICAgICAgYWFbIiJdID0gMTsKICAgICAgICBhYVtmcm9tXSA9IDE7CiAgICB9IGVsc2UgewogICAgICAgIGNvbnN0IGF1dG8gZiA9IGNvdW50KGZyb21bMC4uKCQvMildKTsKICAgICAgICBjb25zdCBhdXRvIGwgPSBjb3VudChmcm9tWygkLzIpLi4kXSk7CiAgICAgICAgZm9yZWFjaCAoaW5mOyB0YXJnZXRJbmZpeGVzKSB7CiAgICAgICAgICAgIGFhW2luZl0gPSAwOwogICAgICAgICAgICBmb3IgKHNpemVfdCBpID0gMDsgaSA8PSBpbmYubGVuZ3RoOyArK2kpIHsKICAgICAgICAgICAgICAgIGFhW2luZl0gKz0gZltpbmZbMC4uaV1dICogbFtpbmZbaS4uJF1dOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQogICAgbWVtb0FBc1tmcm9tXSA9IGFhOwogICAgcmV0dXJuIGFhOwp9CgpzdHJpbmdbXSBpbmZpeGVzKHN0cmluZyBzKSBAc2FmZSB7CiAgICBpbXBvcnQgc3RkLmFycmF5OwogICAgYXV0byBhID0gYXBwZW5kZXIhKHN0cmluZ1tdKTsKICAgIHNpemVfdCBpID0gMDsKICAgIHNpemVfdCBlID0gMDsKICAgIHdoaWxlIChpICE9IHMubGVuZ3RoKSB7CiAgICAgICAgYS5wdXQoc1tpLi5lXSk7CiAgICAgICAgaWYgKGUgPT0gcy5sZW5ndGgpewogICAgICAgICAgICArK2k7IGUgPSBpICsgMTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICArK2U7CiAgICAgICAgfQogICAgfQogICAgcmV0dXJuIGEuZGF0YTsKfQoKdm9pZCBtYWluKCkgQHNhZmUgewogICAgaW1wb3J0IHN0ZC5zdGRpbyA6IHdyaXRlbG47CiAgICBpbXBvcnQgc3RkLnV0ZiA6IHRvVVRGODsKICAgIGltcG9ydCBzdGQucmFuZ2UgOiBqb2luLCByZXBlYXQ7CgogICAgYXV0byBvZGFpID0gIm9kYWkiOwogICAgYXV0byBzcyA9IFsgIm9kYWRhaSIsICJvZGFpb2RhaSIsICJvb29vZGRkZGFhYWFpaWlpIiwgImRhaW9hZGlhbyIgXTsKICAgIHRhcmdldEluZml4ZXMgPSBpbmZpeGVzKG9kYWkpOwoKICAgIGZvcmVhY2ggKHM7IHNzKSB7CiAgICAgICAgc3RyaW5nIHQgPSBzLnJlcGVhdCgxMDAwKS5qb2luLnRvVVRGODsKICAgICAgICB3cml0ZWxuKGNvdW50KHQpW29kYWldKTsKICAgIH0KfQo=