import java.util.*;
class Discuss {
// suffix array in O(n*log^2(n))
public static Integer[] suffixArray
(CharSequence s
) { int n = s.length();
int[] rank = new int[n];
for (int i = 0; i < n; i++) {
sa[i] = i;
rank[i] = s.charAt(i);
}
for (int len = 1; len < n; len *= 2) {
long[] rank2 = new long[n];
for (int i = 0; i < n; i++)
rank2[i] = ((long) rank[i] << 32) + (i + len < n ? rank[i + len] + 1 : 0);
//Arrays.sort(sa, (a, b) -> Long.compare(rank2[a], rank2[b]));
class MyComparator implements Comparator<Integer> {
private final long[] array;
public MyComparator(long[] array)
{
this.array = array;
}
@Override
{
return Long.
compare(array
[index1
],array
[index2
]); }
}
MyComparator comp = new MyComparator(rank2);
for (int i = 0; i < n; i++)
rank[sa[i]] = i > 0 && rank2[sa[i - 1]] == rank2[sa[i]] ? rank[sa[i - 1]] : i;
}
return sa;
}
// random test
public static void main
(String[] args
) { for (int step = 0; step < 100000; step++) {
int n = rnd.nextInt(100);
StringBuilder s = new StringBuilder();
for (int i = 0; i < n; i++)
s.append((char) ('\0' + rnd.nextInt(10)));
for (int i = 0; i + 1 < n; i++)
if (s.substring(sa[i]).compareTo(s.substring(sa[i + 1])) >= 0)
}
System.
out.
println("Test passed"); }
}
aW1wb3J0IGphdmEudXRpbC4qOwoKY2xhc3MgRGlzY3VzcyB7CgogIC8vIHN1ZmZpeCBhcnJheSBpbiBPKG4qbG9nXjIobikpCiAgcHVibGljIHN0YXRpYyBJbnRlZ2VyW10gc3VmZml4QXJyYXkoQ2hhclNlcXVlbmNlIHMpICB7CiAgICBpbnQgbiA9IHMubGVuZ3RoKCk7CiAgICBJbnRlZ2VyW10gc2EgPSBuZXcgSW50ZWdlcltuXTsKICAgIGludFtdIHJhbmsgPSBuZXcgaW50W25dOwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspIHsKICAgICAgc2FbaV0gPSBpOwogICAgICByYW5rW2ldID0gcy5jaGFyQXQoaSk7CiAgICB9CiAgICBmb3IgKGludCBsZW4gPSAxOyBsZW4gPCBuOyBsZW4gKj0gMikgewogICAgICBsb25nW10gcmFuazIgPSBuZXcgbG9uZ1tuXTsKICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspCiAgICAgICAgcmFuazJbaV0gPSAoKGxvbmcpIHJhbmtbaV0gPDwgMzIpICsgKGkgKyBsZW4gPCBuID8gcmFua1tpICsgbGVuXSArIDEgOiAwKTsKCiAgICAgIC8vQXJyYXlzLnNvcnQoc2EsIChhLCBiKSAtPiBMb25nLmNvbXBhcmUocmFuazJbYV0sIHJhbmsyW2JdKSk7CiAgICAgIAogICAgICBjbGFzcyBNeUNvbXBhcmF0b3IgaW1wbGVtZW50cyBDb21wYXJhdG9yPEludGVnZXI+IHsKICAgIAkgICAgICBwcml2YXRlIGZpbmFsIGxvbmdbXSBhcnJheTsKICAgIAkgICAgICBwdWJsaWMgTXlDb21wYXJhdG9yKGxvbmdbXSBhcnJheSkKICAgIAkgICAgICB7CiAgICAJICAgICAgICAgIHRoaXMuYXJyYXkgPSBhcnJheTsKICAgIAkgICAgICB9CgogICAgCSAgICAgIEBPdmVycmlkZQogICAgCSAgICAgIHB1YmxpYyBpbnQgY29tcGFyZShJbnRlZ2VyIGluZGV4MSwgSW50ZWdlciBpbmRleDIpCiAgICAJICAgICAgewogICAgCSAgICAgICAgICByZXR1cm4gTG9uZy5jb21wYXJlKGFycmF5W2luZGV4MV0sYXJyYXlbaW5kZXgyXSk7CiAgICAJICAgICAgfQogICAgCSAgfQogICAgICAKICAgICAgTXlDb21wYXJhdG9yIGNvbXAgPSBuZXcgTXlDb21wYXJhdG9yKHJhbmsyKTsKICAgICAgQXJyYXlzLnNvcnQoc2EsIGNvbXApOwoKCiAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbjsgaSsrKQogICAgICAgIHJhbmtbc2FbaV1dID0gaSA+IDAgJiYgcmFuazJbc2FbaSAtIDFdXSA9PSByYW5rMltzYVtpXV0gPyByYW5rW3NhW2kgLSAxXV0gOiBpOwogICAgfQogICAgcmV0dXJuIHNhOwogIH0KICAKCiAgLy8gcmFuZG9tIHRlc3QKICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICBSYW5kb20gcm5kID0gbmV3IFJhbmRvbSgxKTsKICAgIGZvciAoaW50IHN0ZXAgPSAwOyBzdGVwIDwgMTAwMDAwOyBzdGVwKyspIHsJCiAgICAgIGludCBuID0gcm5kLm5leHRJbnQoMTAwKTsKICAgICAgU3RyaW5nQnVpbGRlciBzID0gbmV3IFN0cmluZ0J1aWxkZXIoKTsKICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspCiAgICAgICAgcy5hcHBlbmQoKGNoYXIpICgnXDAnICsgcm5kLm5leHRJbnQoMTApKSk7CiAgICAgIEludGVnZXJbXSBzYSA9IHN1ZmZpeEFycmF5KHMpOwogICAgICBmb3IgKGludCBpID0gMDsgaSArIDEgPCBuOyBpKyspCiAgICAgICAgaWYgKHMuc3Vic3RyaW5nKHNhW2ldKS5jb21wYXJlVG8ocy5zdWJzdHJpbmcoc2FbaSArIDFdKSkgPj0gMCkKICAgICAgICAgIHRocm93IG5ldyBSdW50aW1lRXhjZXB0aW9uKCk7CiAgICB9CiAgICBTeXN0ZW0ub3V0LnByaW50bG4oIlRlc3QgcGFzc2VkIik7CiAgfQp9