/*
Copyright 2013 Jakub "Cubix651" Cisło
Dictionary of base factors (DBF)
Complexity: O(n log n + q log n)
This algorithm is impractical, a better way is coding DBF
using STL in complexity O(n log^2 n) - it's easier
and the difference in speed is invisible.
*/
#include <cstdio>
#include <cstring>
#include <vector>
#define PB push_back
using namespace std;
const int MAXLEN = 500007, LOG = 30, SIGMA = 1000007;
int dbf[MAXLEN][LOG];
vector<vector<int> > countingSort(vector<vector<int> > tab, int size, int idx)
{
vector<vector<int> > res;
res.resize(size);
for(int i = 0; i < size; ++i)
res[i] = vector<int>();
int cnt[SIGMA], tmp;
for(int i = 0; i < SIGMA; ++i)
cnt[i] = 0;
for(int i = 0; i < size; ++i)
++cnt[tab[i][idx]];
for(int i = 1; i < SIGMA; ++i)
cnt[i] += cnt[i-1];
for(int i = SIGMA-1; i > 0; --i)
cnt[i] = cnt[i-1];
cnt[0] = 0;
for(int i = 0; i < size; ++i)
res[cnt[tab[i][idx]]++] = tab[i];
return res;
}
vector<vector<int> > radixSort(vector<vector<int> > tab, int size, int k)
{
for(int i = k-1; i >= 0; --i)
tab = countingSort(tab, size, i);
return tab;
}
void DBF(char *s, int size)
{
for(int i = 0; i < size; ++i)
dbf[i][0] = s[i]-'a';
int len = 1, idx = 1;
vector<vector<int> > vec;
vec.resize(size);
while(2*len <= size)
{
for(int i = 0; i + 2*len <= size; ++i)
{
vec[i] = vector<int>();
vec[i].PB(dbf[i][idx-1]);
vec[i].PB(dbf[i+len][idx-1]);
vec[i].PB(i);
}
vec = radixSort(vec, size - 2*len + 1, 2);
dbf[vec[0][2]][idx] = 0;
for(int i = 1; i + 2*len <= size; ++i)
dbf[vec[i][2]][idx] = dbf[vec[i-1][2]][idx] + ((vec[i][0]==vec[i-1][0] && vec[i][1]==vec[i-1][1])?0:1);
++idx;
len <<= 1;
}
}
bool equal(int a, int b, int s)
{
if(a == b || s == 0)
return true;
//this part can be preprocessed and complexity will O(n log n + q)
int pow = 1, idx = -1;
while(pow <= s)
{
pow <<= 1;
++idx;
}
pow >>= 1;
return ((dbf[a][idx] == dbf[b][idx]) && (dbf[a+s-pow][idx] == dbf[b+s-pow][idx]));
}
int main()
{
char *str = "abbaabbabababbaaaba";
DBF(str, strlen(str));
printf("%s\n", equal(3, 15, 3) ? "tak" : "nie");
printf("%s\n", equal(3, 15, 4) ? "tak" : "nie");
return 0;
}
LyogCiAgIENvcHlyaWdodCAyMDEzIEpha3ViICJDdWJpeDY1MSIgQ2lzxYJvCiAgIERpY3Rpb25hcnkgb2YgYmFzZSBmYWN0b3JzIChEQkYpCiAgIENvbXBsZXhpdHk6IE8obiBsb2cgbiArIHEgbG9nIG4pCiAgIAogICBUaGlzIGFsZ29yaXRobSBpcyBpbXByYWN0aWNhbCwgYSBiZXR0ZXIgd2F5IGlzIGNvZGluZyBEQkYKICAgdXNpbmcgU1RMIGluIGNvbXBsZXhpdHkgTyhuIGxvZ14yIG4pIC0gaXQncyBlYXNpZXIKICAgYW5kIHRoZSBkaWZmZXJlbmNlIGluIHNwZWVkIGlzIGludmlzaWJsZS4KKi8KI2luY2x1ZGUgPGNzdGRpbz4KI2luY2x1ZGUgPGNzdHJpbmc+CiNpbmNsdWRlIDx2ZWN0b3I+CiNkZWZpbmUgUEIgcHVzaF9iYWNrCnVzaW5nIG5hbWVzcGFjZSBzdGQ7Cgpjb25zdCBpbnQgTUFYTEVOID0gNTAwMDA3LCBMT0cgPSAzMCwgU0lHTUEgPSAxMDAwMDA3OwppbnQgZGJmW01BWExFTl1bTE9HXTsKCnZlY3Rvcjx2ZWN0b3I8aW50PiA+IGNvdW50aW5nU29ydCh2ZWN0b3I8dmVjdG9yPGludD4gPiB0YWIsIGludCBzaXplLCBpbnQgaWR4KQp7Cgl2ZWN0b3I8dmVjdG9yPGludD4gPiByZXM7CglyZXMucmVzaXplKHNpemUpOwoJZm9yKGludCBpID0gMDsgaSA8IHNpemU7ICsraSkKCQlyZXNbaV0gPSB2ZWN0b3I8aW50PigpOwoJCglpbnQgY250W1NJR01BXSwgdG1wOwoJZm9yKGludCBpID0gMDsgaSA8IFNJR01BOyArK2kpCgkJY250W2ldID0gMDsKCWZvcihpbnQgaSA9IDA7IGkgPCBzaXplOyArK2kpCgkJKytjbnRbdGFiW2ldW2lkeF1dOwoJZm9yKGludCBpID0gMTsgaSA8IFNJR01BOyArK2kpCgkJY250W2ldICs9IGNudFtpLTFdOwoJZm9yKGludCBpID0gU0lHTUEtMTsgaSA+IDA7IC0taSkKCQljbnRbaV0gPSBjbnRbaS0xXTsKCWNudFswXSA9IDA7Cglmb3IoaW50IGkgPSAwOyBpIDwgc2l6ZTsgKytpKQoJCXJlc1tjbnRbdGFiW2ldW2lkeF1dKytdID0gdGFiW2ldOwoJcmV0dXJuIHJlczsKfQoKdmVjdG9yPHZlY3RvcjxpbnQ+ID4gcmFkaXhTb3J0KHZlY3Rvcjx2ZWN0b3I8aW50PiA+IHRhYiwgaW50IHNpemUsIGludCBrKQp7Cglmb3IoaW50IGkgPSBrLTE7IGkgPj0gMDsgLS1pKQoJCXRhYiA9IGNvdW50aW5nU29ydCh0YWIsIHNpemUsIGkpOwoJcmV0dXJuIHRhYjsKfQoKdm9pZCBEQkYoY2hhciAqcywgaW50IHNpemUpCnsKCWZvcihpbnQgaSA9IDA7IGkgPCBzaXplOyArK2kpCgkJZGJmW2ldWzBdID0gc1tpXS0nYSc7CgkKCWludCBsZW4gPSAxLCBpZHggPSAxOwoJdmVjdG9yPHZlY3RvcjxpbnQ+ID4gdmVjOwoJCgl2ZWMucmVzaXplKHNpemUpOwoJCgkKCXdoaWxlKDIqbGVuIDw9IHNpemUpCgl7CgkJZm9yKGludCBpID0gMDsgaSArIDIqbGVuIDw9IHNpemU7ICsraSkKCQl7CgkJCXZlY1tpXSA9IHZlY3RvcjxpbnQ+KCk7CgkJCXZlY1tpXS5QQihkYmZbaV1baWR4LTFdKTsKCQkJdmVjW2ldLlBCKGRiZltpK2xlbl1baWR4LTFdKTsKCQkJdmVjW2ldLlBCKGkpOwoJCX0KCQkKCQl2ZWMgPSByYWRpeFNvcnQodmVjLCBzaXplIC0gMipsZW4gKyAxLCAyKTsKCQkKCQlkYmZbdmVjWzBdWzJdXVtpZHhdID0gMDsKCQlmb3IoaW50IGkgPSAxOyBpICsgMipsZW4gPD0gc2l6ZTsgKytpKQoJCQlkYmZbdmVjW2ldWzJdXVtpZHhdID0gZGJmW3ZlY1tpLTFdWzJdXVtpZHhdICsgKCh2ZWNbaV1bMF09PXZlY1tpLTFdWzBdICYmIHZlY1tpXVsxXT09dmVjW2ktMV1bMV0pPzA6MSk7CgkJCgkJKytpZHg7CgkJbGVuIDw8PSAxOwoJfQp9Cgpib29sIGVxdWFsKGludCBhLCBpbnQgYiwgaW50IHMpCnsKCWlmKGEgPT0gYiB8fCBzID09IDApCgkJcmV0dXJuIHRydWU7CgkKCS8vdGhpcyBwYXJ0IGNhbiBiZSBwcmVwcm9jZXNzZWQgYW5kIGNvbXBsZXhpdHkgd2lsbCBPKG4gbG9nIG4gKyBxKQoJaW50IHBvdyA9IDEsIGlkeCA9IC0xOwoJd2hpbGUocG93IDw9IHMpCgl7CgkJcG93IDw8PSAxOwoJCSsraWR4OwoJfQoJcG93ID4+PSAxOwoJcmV0dXJuICgoZGJmW2FdW2lkeF0gPT0gZGJmW2JdW2lkeF0pICYmIChkYmZbYStzLXBvd11baWR4XSA9PSBkYmZbYitzLXBvd11baWR4XSkpOwp9CgppbnQgbWFpbigpCnsKCWNoYXIgKnN0ciA9ICJhYmJhYWJiYWJhYmFiYmFhYWJhIjsKCURCRihzdHIsIHN0cmxlbihzdHIpKTsKCXByaW50ZigiJXNcbiIsIGVxdWFsKDMsIDE1LCAzKSA/ICJ0YWsiIDogIm5pZSIpOwoJcHJpbnRmKCIlc1xuIiwgZXF1YWwoMywgMTUsIDQpID8gInRhayIgOiAibmllIik7CglyZXR1cm4gMDsKfQ==