把全部僅包含\(AB\)的字符串按字典序排列,給你一個僅包含\(AB\)的字符串\(S\),而後有\(Q\)個問題,第\(i\)個問題給你\(k_i\),求不是\(S\)的子串中,第\(k_i\)小的是什麼。\(T\)組數據ios
\(T\leqslant5\),\(\sum|S_i|\leqslant2.3\times10^5\),\(Q_i\leqslant10\),\(k_i\leqslant10^9\)spa
發現,長度爲\(l\)的字符串有\(2^l\)個,而\(S\)的長度小於等於\(l\)的子串最多有\(l|S|\)個,能夠發現,當\(l>31\)時\(2^l-l|S|>10^9\),即答案長度必定小於等於\(31\)。由於字符串中只含有\(AB\),能夠用二進制表示,用\(\mathrm{hash}\)算出\(S\)中每種長度的子串。這樣能夠算出最終的答案的長度,而後在這一個長度中二分便可。code
多測必定要清空!!ci
#include <cstdio> #include <iostream> #include <algorithm> int T, n, Q, k, p; int s[32][250000], cnt[32]; std::string __s; bool check(int mid, int p) { return mid + 1 - (std::upper_bound(s[p], s[p] + cnt[p], mid) - s[p]) >= k; } int main() { std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); std::cin >> T; while (T --> 0) { std::cin >> __s, n = __s.length(); for (int i = 1; i <= 31 && i <= n; ++i) { const int I = (1 << i) - 1; s[i][0] = 0; for (int j = 0; j < i; ++j) s[i][0] = s[i][0] << 1 | __s[j] - 'A'; for (int j = i; j < n; ++j) s[i][j - i + 1] = (s[i][j - i] << 1 | __s[j] - 'A') & I; std::sort(s[i], s[i] + n - i + 1); cnt[i] = std::unique(s[i], s[i] + n - i + 1) - s[i]; } std::cin >> Q; while (Q --> 0) { std::cin >> k; for (p = 1; p <= 31; ++p) if ((1 << p) - cnt[p] < k) k -= (1 << p) - cnt[p]; else break; int l = 0, r = (1 << p) - 1, ans = -1; while (l <= r) { int mid = l + r >> 1; if (check(mid, p)) ans = mid, r = mid - 1; else l = mid + 1; } for (int i = p - 1; ~i; --i) std::cout << "AB"[ans >> i & 1]; std::cout.put('\n'); } for (int i = 1; i <= 31; ++i) cnt[i] = 0; } return 0; }