# Super Kth LISĀ – HackerRank Solution Java , Python 3, Python 2 , C , C++, Best and Optimal Solutions , All you need.

# Solutions of Algorithms Data Structures Hard HackerRank:

## Here are all the Solutions of Hard , Advanced , Expert Algorithms of Data Structure of Hacker Rank , Leave a comment for similar posts

# C++ replace HackerRank Solution

#include <algorithm> #include <cassert> #include <cstring> #include <iostream> using namespace std; #define FOR(i, a, b) for (int i = (a); i < (b); ++i) #define REP(i, n) FOR(i, 0, n) #define TRACE(x) cout << #x << " = " << x << endl #define _ << " _ " << typedef long long llint; const int MAX = 100100; const llint inf = 2e18; int L[MAX]; int getMax(int x) { int r = 0; for (++x; x; x -= x&-x) r = max(r, L[x]); return r; } void update(int x, int v) { for (++x; x < MAX; x += x&-x) L[x] = max(L[x], v); } llint S[MAX]; llint add(llint x, llint y) { return min(inf, x + y); } llint mul(llint x, llint y) { if (x == 0 || y == 0) return 0; if (x < (inf + y - 1) / y) return min(x * y, inf); return inf; } llint sum(int x) { llint r = 0; for (++x; x; x -= x&-x) r = add(r, S[x]); return r; } void add(int x, llint v) { for (++x; x < MAX; x += x&-x) S[x] = add(S[x], v); } void clear(int x) { for (++x; x < MAX; x += x&-x) S[x] = 0; } int a[MAX]; int f[MAX]; llint g[MAX]; vector<int> v[MAX]; int main(void) { int N; llint K; scanf("%d %lld", &N, &K); REP(i, N) scanf("%d", &a[i]); for (int i = N-1; i >= 0; --i) { f[i] = getMax(N-a[i]-1) + 1; update(N-a[i], f[i]); } int L = getMax(N); REP(i, N) v[f[i]].push_back(i); for (int i = 1; i <= L; ++i) { int p = (int)v[i - 1].size() - 1; for (int j = (int)v[i].size() - 1; j >= 0; --j) { while (p >= 0 && v[i-1][p] > v[i][j]) { add(N-a[v[i-1][p]], g[v[i-1][p]]); p--; } if (i == 1) g[v[i][j]] = 1; else g[v[i][j]] = sum(N-a[v[i][j]]-1); } while (++p < (int)v[i-1].size()) clear(N-a[v[i-1][p]]); } llint total = 0; for (int x: v[L]) total = add(total, g[x]); if (total < K) { puts("-1"); return 0; } vector<pair<int, llint>> cur = {{-1, 1}}; vector<int> ans; int last = 0; for (int i = L; i > 0; --i) { auto count = [&] (int x) { int p = (int)v[i].size() - 1; llint total = 0; llint rsum = 0; for (int j = (int)cur.size() - 1; j >= 0; --j) { while (p >= 0 && v[i][p] > cur[j].first) { if (last < a[v[i][p]] && a[v[i][p]] <= x) rsum = add(rsum, g[v[i][p]]); p--; } total = add(total, mul(rsum, cur[j].second)); } return total; }; int lo = last + 1, hi = N; while (lo < hi) { int mid = (lo + hi) / 2; if (count(mid) < K) lo = mid + 1; else hi = mid; } K -= count(lo - 1); vector<pair<int, llint>> ncur; int p = 0; llint rsum = 0; REP(j, (int)v[i].size()) { while (p < (int)cur.size() && cur[p].first < v[i][j]) rsum = add(rsum, cur[p++].second); if (a[v[i][j]] == lo) ncur.push_back({v[i][j], rsum}); } cur = ncur; ans.push_back(lo); last = lo; } for (int x: ans) printf("%d ", x); printf("\n"); return 0; }

# Java rep HackerRank Solution

import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Arrays; import java.util.Comparator; import java.util.InputMismatchException; public class E { InputStream is; PrintWriter out; String INPUT = ""; static long I = 2000000000_000000000L; void solve() { int n = ni(); long K = nl(); int[] a = na(n); int[] b = Arrays.copyOf(a, n); for(int i = 0;i < n;i++)b[i] = n-a[n-1-i]; b = shrink(b); // for(int i = 0;i < n;i++)b[i]++; SegmentTreeRMQSumWhenMax st = new SegmentTreeRMQSumWhenMax(n+5); st.updateOrAdd(0, 0, 1); // shifted by 1 int[] maxs = new int[n+1]; long[] counts = new long[n+1]; double[] cx = new double[n+1]; for(int i = 0;i < n;i++){ int max = st.maxx(0, b[i]+1); // <=a[i] maxs[i] = max; if(st.gwd >= I)st.gw = I; counts[i] = st.gw; cx[i] = st.gwd; st.updateOrAdd(b[i]+1, max+1, st.gw); } int max = st.maxx(0, n+1); // <=a[i] maxs[n] = max; counts[n] = st.gw; cx[n] = st.gwd; if(cx[n] <= 2E18 && K > counts[n]){ out.println(-1); return; } int lis = maxs[n]; int[][] g = makeBuckets(maxs, lis); for(int i = 0;i < n+1;i++){ if(cx[i] >= 2E18){ counts[i] = I; } } long[] ft = new long[n+3]; double[] ftd = new double[n+3]; addFenwick(ft, 0, 1); addFenwick(ftd, 0, 1); int[] ret = new int[lis]; int[] prevs = new int[n]; long[] pvs = new long[n]; int pp = 0; prevs[pp] = 0; pvs[pp] = 1; pp++; for(int h = lis-1;h >= 0;h--){ long[][] temps = new long[g[h].length][]; int p = 0; for(int i : g[h]){ int ind = n-1-i; if(h < lis-1 && a[ind] <= ret[lis-(h+1)-1])continue; long sum = sumFenwick(ft, ind+1); double sumd = sumFenwick(ftd, ind+1); if(sumd >= I)sum = I; long cc = sum*counts[i]; double cd = (double)counts[i]*sum; if(cd > 2E18){ cc = I; } temps[p++] = new long[]{a[ind], cc, sum, ind+1}; } for(int j = 0;j < pp;j++){ addFenwick(ft, prevs[j], -pvs[j]); addFenwick(ftd, prevs[j], -pvs[j]); } // 1 4 5 3 5 Arrays.sort(temps, 0, p, new Comparator<long[]>() { public int compare(long[] a, long[] b) { return Long.compare(a[0], b[0]); } }); // tr("temps", temps); for(int i = 0;i < p;){ int j = i; while(j < p && temps[j][0] == temps[i][0])j++; long lnum = 0; for(int k = i;k < j;k++){ lnum += temps[k][1]; if(lnum >= I)lnum = I; } if(K - lnum <= 0){ ret[lis-h-1] = (int)temps[i][0]; break; }else{ K -= lnum; } i = j; } pp = 0; for(int i = 0;i < p;i++){ long[] t = temps[i]; if(t[0] == ret[lis-h-1]){ // tr("add", t); addFenwick(ft, (int)t[3], t[2]); addFenwick(ftd, (int)t[3], t[2]); prevs[pp] = (int)t[3]; pvs[pp] = t[2]; pp++; } } } // tr(g); // tr(maxs); // tr(counts); for(int i = 0;i < lis;i++){ out.print(ret[i] + " "); } out.println(); // tr(K); } public static long sumFenwick(long[] ft, int i) { long sum = 0; for(i++;i > 0;i -= i&-i){ sum += ft[i]; } return sum; } public static void addFenwick(long[] ft, int i, long v) { if(v == 0)return; int n = ft.length; for(i++;i < n;i += i&-i)ft[i] += v; } public static double sumFenwick(double[] ft, int i) { double sum = 0; for(i++;i > 0;i -= i&-i){ sum += ft[i]; } return sum; } public static void addFenwick(double[] ft, int i, double v) { if(v == 0)return; int n = ft.length; for(i++;i < n;i += i&-i)ft[i] += v; } public static int[][] makeBuckets(int[] a, int sup) { int n = a.length; int[][] bucket = new int[sup+1][]; int[] bp = new int[sup+1]; for(int i = 0;i < n;i++)bp[a[i]]++; for(int i = 0;i <= sup;i++)bucket[i] = new int[bp[i]]; for(int i = n-1;i >= 0;i--)bucket[a[i]][--bp[a[i]]] = i; return bucket; } public static int[] shrink(int[] a) { int n = a.length; long[] b = new long[n]; for (int i = 0; i < n; i++) b[i] = (long) a[i] << 32 | i; Arrays.sort(b); int[] ret = new int[n]; int p = 0; for (int i = 0; i < n; i++) { if (i > 0 && (b[i] ^ b[i - 1]) >> 32 != 0) p++; ret[(int) b[i]] = p; } return ret; } private static class SegmentTreeRMQSumWhenMax { public int M, H, N; public int[] st; public long[] w; public double[] wd; public SegmentTreeRMQSumWhenMax(int n) { N = n; M = Integer.highestOneBit(Math.max(N-1, 1))<<2; H = M>>>1; st = new int[M]; w = new long[M]; wd = new double[M]; Arrays.fill(st, 0, M, Integer.MIN_VALUE); } // if x equals to before st[H+pos], +y, else update y public void updateOrAdd(int pos, int x, long y) { if(x < st[H+pos])throw new RuntimeException("x < st[H+pos]"); if(x == st[H+pos]){ w[H+pos] += y; wd[H+pos] += y; }else{ st[H+pos] = x; w[H+pos] = y; // y % mod wd[H+pos] = y; // y % mod } for(int i = (H+pos)>>>1;i >= 1;i >>>= 1)propagate(i); } private void propagate(int i) { if(st[2*i] < st[2*i+1]){ st[i] = st[2*i+1]; w[i] = w[2*i+1]; wd[i] = wd[2*i+1]; }else if(st[2*i] > st[2*i+1]){ st[i] = st[2*i]; w[i] = w[2*i]; wd[i] = wd[2*i]; }else{ st[i] = st[2*i]; w[i] = w[2*i] + w[2*i+1]; wd[i] = wd[2*i] + wd[2*i+1]; } } public long gw; public double gwd; public int maxx(int l, int r){ gw = 0; gwd = 0.; if(l >= r)return 0; int max = Integer.MIN_VALUE; while(l != 0){ int f = l&-l; if(l+f > r)break; int v = st[(H+l)/f]; if(v > max){ max = v; gw = w[(H+l)/f]; gwd = wd[(H+l)/f]; }else if(v == max){ gw += w[(H+l)/f]; gwd += wd[(H+l)/f]; } l += f; } while(l < r){ int f = r&-r; int v = st[(H+r)/f-1]; if(v > max){ max = v; gw = w[(H+r)/f-1]; gwd = wd[(H+r)/f-1]; }else if(v == max){ gw += w[(H+r)/f-1]; gwd += wd[(H+r)/f-1]; } r -= f; } return max; } } void run() throws Exception { is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes()); out = new PrintWriter(System.out); long s = System.currentTimeMillis(); solve(); out.flush(); if(!INPUT.isEmpty())tr(System.currentTimeMillis()-s+"ms"); } public static void main(String[] args) throws Exception { new E().run(); } private byte[] inbuf = new byte[1024]; private int lenbuf = 0, ptrbuf = 0; private int readByte() { if(lenbuf == -1)throw new InputMismatchException(); if(ptrbuf >= lenbuf){ ptrbuf = 0; try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); } if(lenbuf <= 0)return -1; } return inbuf[ptrbuf++]; } private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); } private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; } private double nd() { return Double.parseDouble(ns()); } private char nc() { return (char)skip(); } private String ns() { int b = skip(); StringBuilder sb = new StringBuilder(); while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ') sb.appendCodePoint(b); b = readByte(); } return sb.toString(); } private char[] ns(int n) { char[] buf = new char[n]; int b = skip(), p = 0; while(p < n && !(isSpaceChar(b))){ buf[p++] = (char)b; b = readByte(); } return n == p ? buf : Arrays.copyOf(buf, p); } private char[][] nm(int n, int m) { char[][] map = new char[n][]; for(int i = 0;i < n;i++)map[i] = ns(m); return map; } private int[] na(int n) { int[] a = new int[n]; for(int i = 0;i < n;i++)a[i] = ni(); return a; } private int ni() { int num = 0, b; boolean minus = false; while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-')); if(b == '-'){ minus = true; b = readByte(); } while(true){ if(b >= '0' && b <= '9'){ num = num * 10 + (b - '0'); }else{ return minus ? -num : num; } b = readByte(); } } private long nl() { long num = 0; int b; boolean minus = false; while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-')); if(b == '-'){ minus = true; b = readByte(); } while(true){ if(b >= '0' && b <= '9'){ num = num * 10 + (b - '0'); }else{ return minus ? -num : num; } b = readByte(); } } private static void tr(Object... o) { System.out.println(Arrays.deepToString(o)); } }

# Python 3 rep HackerRank Solution

# Python 2 rep HackerRank Solution

# C rep HackerRank Solution

/* Giving 1 <= n <= 10**5 items ranging in [1 ... n] determine the 1 <= kth <= 10**18 lexicographic increasing sequence of maximal length, i.e. for all increasing sequences whose length is maximal determine the kth entry; print -1 should one not exist; We will start by determining the length of the/a longest increasing sub-sequence ending at each member, we first normalize all entries, i.e. we replace each entry by their distinct rank; (the overall number of distinct entries that are lesser than or equal to itself), while keeping track the original values since this are the ones that must be yielded) this can be done in O(n) time/space by sorting all entries using frequency sort since all entries are lesser than or equal to n; Using a fenwick tree and a scan-line algorithm we can determine the greatest length seen among all those previously processed entries whose normalized items are strictly lesser then the current entry; since this entry would increase all previously seen lesser terminals; implying that the longest length for this new terminal must be 1 greater; after which we update all prefixes that takes into consideration the current normalized entry (i.e. all sucessors) being that the tree must take into consideration all processed lengths; Querying/Updating a fenwick tree takes at most log(k) where k is the number of distinct entries, since we are using normalized entries as our keys, implying this at worst would take O(n * log(k)) time w/ O(n + k) space; Since we are only interested in solutions whose length is the same as the overall max (longest), and for each component of our solution we need to shift to the nearest adjacent, we need to calculate the total number of increasing sub-sequences that start at each member and whose overall length is the same as our overall max length; This can be achieved using a combination of merge sort and scan-line; We arg sort all members by their maximal lengths using a stable sorting algorithm; being that the max length has to be lesser than or equal to n this can be achieved in O(n + max_length) space/time using frequency sort; Initialize the totals to 1 for those members whose lengths exactly match our overall max length, while zeroing the rest; Note that as we merge each ordered member of length l and length l + 1 both in descending manner; (assuming we've initialized the totals of all those whose length is exactly the max to 1; for each member of length l we need to sum the totals of all successors i.e. those of length l + 1 and whose respective entries as strictly greater; we can use a fenwick tree to store the sum of totals among all suffixes with respect to processed successors indexed by their corresponding entry; Implying that as we merge should the current member of length l be further out then the current member of l + 1; then the tree must hold all 'valid' sums; and no other other member of l + 1 need be considered since both sets are being processed in descending order; as such we take sum among all suffixes whose entries are strictly are greater then that of the current member of l; On the other hand should the current member of l + 1 be a successor to the current member of l implying that it would also have to be a successor to all predecessors of the current member of l; we would need to instead update our tree by incrementing all suffixes that the current members entry intercepts (i.e. all those lesser) by this members total; We do this while we still have l + 1 members; after which we processed any remaining l entries, since they would have to be predecessors to all members of l + 1; NOTE that the overall number of solutions can very eassily exceed our precession, though sine we will still be iterating a smaller number of solutions overall (O(rank) < 10**18); we can use saturated arithmetic i.e. should at any time our summation exceed our precession (i.e. we overflow) we will store the largest possible value that can be represented instead; Afterwhich we would need to reset our tree since that at any giving time it only considers the current total among those members having the same length; as such we will iterate over each member of l + 1 that was processed, and actually mutated the tree, i.e. it had a non-zero total; reseting all intercepting NON-ZERO suffixes, as such at no time do we ever processed any distinct path more than our once, since we had always incremented all intercepting suffixes, with a non-zero value; if we traverse this path again and should at any time arrive at a zero entry implies that a previous member must have cleared all further entries; Since either quering/updating a fenwick tree always takes at most O(log(n)) implies that this overall would take O(n * log(k)) since we witness each member at most twice once to query and again to update; since each has exactly one length, and while resetting the tree we only traverse each distinct path at most once; Note in order to determine our answer we would need to at the very least start at the overall smallest sub-sequence which would require for each member to determine the smallest 'valid' successor should their be any collisions we will choose the furthest out, i.e. first seen, while applying our previous merge algorithm; since we want the lexicographically smallest, implies that during collisions, should their be any greater successor that lie between the two occurrences implies that the nearest occurrence may have a greater count, but at the same time also share a 'common' number of solutions with those starting at successive occurrences; as such we only want to move to a preceding occurrence once we've exhausted all possible 'smaller' candidates; i.e. since we want to iterate solutions in lexicographic order should we take the nearest (last) occurrence we ran the risk of iterating sub-sequences out of order since if we assume that our answer lies on the next set of sub-sequences we would consume all those that are in common as well as possibly those that are greater on the other hand if we take the furthest out this can't possibly happen since should we take next set of solutions at the very least we would have to iterate overall those in common first before reaching those that are greater; since for all solutions starting a the first occurrence we can also choose any of the preceding occurrences; Either way this does not change our complexities since we would simply use a second fenwick tree to to store the argmax and query/update it at the same we touch the first tree; After which we can filter all members that failed to generate a maximal length i.e. those whose counts remained zero; leaving behind all the candidates at each possible length; Since at any giving time we want to be able to move to the nearest set of solutions at any giving length; for each possible length we will sort all the remaining members in a stable ascending manner; we note that for any giving pair of members should their entries differ, then the one with the smaller entry should precede the greater, on the other hand should the entries match we would need to determine which would yield the overall min, i.e. iterate up to the nearest different successor, and take which ever yielded the smaller; we can speed things up by storing the index of each member at each distinct length after they are sorted in which case should the pairs entries match we can look at the offset of their respective successors; though if the matching entries have the same member as a successor we will instead use their respective total number of sub-sets, i.e. the one with smaller total should preceed the one with greater; since this smaller number is the number of common solution between the two; This at worse would take O(n log(n)) time w/ O(n) space using merge sort; We start with a candidate by iterating all successors starting at the smallest ordered sub-sequence starting at length 1; Note that the overall number of frequency of solutions is also dependent on the distribution of each preceding member; if at any time our current candidate solution can choose from k members that yield the same solution, each representing all occurrences of the same entry leading to the same successor and each being a successor to the previous entry of our solution implies that the overall total would be the product of this two totals, impliying we would also need to calculate the frequency to which this prefix may occur while each being valid to the current suffix; which can be determined while scanning all valid candidates, and keeping track their overall product up to each suffix; Now that we can determine the overall number of sub-sets that are lesser than or equal to some prefix of our solution we can binary search for the nearest suffix whose overall total being (the product frequency of its current prefix and the number of sub-sequences that start at its self) is greater than our rank; implying that at the very least this prefix 'may' remain and we would need to shift its successor to the next set of solutions, since they are each sorted implies if this successors neighbor exists it must contain at the very least the same sub-set of solutions as the original entry; of which we remove from our rank, though if none are available implies that we are at the end of our prefix we would need to search for the nearest predecessor with an available neighbor should none exists implies that we must have exhausted all solutions, as such we set our solution to -1 and terminate; After replacing the successor with a valid neighbor we would need to update all prefix frequencies as well as suffixes starting at this updated point; since the swap values may not point to the same successor, and/or change the distribution of items; Eitherway we repeat until we've either exhausted all solutions in which case we print -1 or our current solution has an overall frequency smaller or equal to our rank; in which case this must be our solution since we're always consuming sets of solutions either with equal or greater lexicographic rank; The complexity of this algorithm is a bit tricky, determining the prefix frequencies takes at worse O(n) since we can simply scan for all valid candidates at each component of our solution; at first glance it seems O(n**2) if we always end up at the first (smallest) component, then we would need to rebuild our solution though obviously if our max length was n, then this can only occur at most once, since we could only have 1 initial component, on the other hand if we have m initial components and our max length is l with c overall candidate components then this would take O(m * (l + c)) since l <= c implying O(m * c), should m = n/2 and c = n/2 in the case where we have n/2 duplicate mins followed by a common suffix (i.e. a strictly increasing sub-sequence of length n/2), and giving a rank exceeding all possible solutions then indeed this would take O(n**2) being that we would have O((n/2) * ((n/2) + log(n/2))) <=> O(n**2) Therefore lets store the prefix frequencies in a fenwick tree where each of its nodes store the product of all its descendant/prefix frequencies indexed by the components offset into the current solution, this would increase our prefix counts from O(n) to O(n * log(max_length)) and our binary search for the nearest overflowed suffix from O(n * log(max_length)) to O(n * log(max_length)**2) since for each query point we would have to also query the second tree to determine the prefix frequency; though now if we where to update a member whose frequency is greater than 1, since we know its neighbor had to have the same successor we need only to update our fenwick tree of products by first removing the previous frequency, i.e. dividing all intercepting prefixes and adding the new frequency being 1 unit lesser, this would take at worse O(log(max_length)), reducing our time complexity to O(n * (log(n)**2 + log(n)) (if we always land on members with frequencies) Still if we where to update an entry whose frequency was 1, instead of rebuilding the rest of our solution we note if at any time we reach a previously matching successor (assuming we've updated its all previous frequencies) then implies that the rest of our solution would remain the same as such we can halt here, implying at worse we are only updating delta components. Note that we need to take great care when moving between set of solutions since there could be many candidates that yield the same total lesser than our current rank; though being we are looking for the next smallest set of solutions implies we should search for the furthest suffix that both yield the same total and has a valid neighbor with our current prefix, since each candidate was sorted assuming to have no prefix, it could be the case that the nearest smaller neighbor may require a greater prefix, should it start before our prefix invalidating our previous assumption of consume sets in a monotonic fashion; */ #include <stdio.h> #include <string.h> #include <stdlib.h> #pragma GCC optimize("O2") unsigned long sat_prod(unsigned long self, unsigned long factor) { if ((self < 0x100000000UL) && (factor < 0x100000000UL)) return (self * factor); if (((__builtin_clzl(self) ^ 63U) + (__builtin_clzl(factor) ^ 63U)) >= 64) return 0xFFFFFFFFFFFFFFFFUL; if (self < factor) { self ^= factor; factor ^= self; self ^= factor; } // a * b; b <=> (b[0]*2**0 + b[1]*2**1 + ... + b[k]*2**k) // => a*b[0]*2**0 + a*b[1]*2**1 + .... + a*b[k]*2**k unsigned long product = 0; for (; factor; factor >>= 1, self <<= 1) { if (factor & 1) { if (product > (0xFFFFFFFFFFFFFFFFUL ^ self)) return 0xFFFFFFFFFFFFFFFFUL; product += self; } if ((self & 0x8000000000000000UL) && (factor > 1)) return 0xFFFFFFFFFFFFFFFFUL; } return product; } void descending_stbl( unsigned cnt, unsigned *self, unsigned *items, unsigned *smallest, unsigned *largest, unsigned *offsets ) { unsigned at, span, at_left, at_right, *left, *right, order[cnt]; for (span = 1; span < cnt; span <<= 1) { left = &((unsigned *)memcpy(order, self, sizeof(order)))[(at = cnt) - 1]; for (right = &left[span]; at > span; ) { right -= (span << 1); at_left = (at < (span << 1)) ? (at - span) : span; for (left -= (at_left + (at_right = span)); at_left && at_right; ) if (items[left[at_left]] == items[right[at_right]]) { if (smallest[left[at_left]] == smallest[right[at_right]]) { if (largest[left[at_left]] == largest[right[at_right]]) self[--at] = right[at_right--]; else self[--at] = (offsets[largest[left[at_left]]] > offsets[largest[right[at_right]]]) ? left[at_left--] : right[at_right--]; } else self[--at] = (offsets[smallest[left[at_left]]] > offsets[smallest[right[at_right]]]) ? left[at_left--] : right[at_right--]; } else self[--at] = (items[left[at_left]] < items[right[at_right]]) ? left[at_left--] : right[at_right--]; memcpy(&self[at -= (at_left | at_right)], &right[1], at_right * sizeof(self[0])); } } } int main() { unsigned cnt; unsigned long rank; scanf("%u %lu", &cnt, &rank); unsigned at, others, tail, next, items[cnt + 1]; for (tail = 0, at = cnt; at--; ) if (tail < ((void)scanf("%u", &items[at]), items[at])) tail = items[at]; unsigned distinct, orig[cnt]; { unsigned ids[++tail]; memset(ids, 0, sizeof(ids)); for (at = cnt; at--; ids[items[at]] = 1); for (; ++at < tail; ids[at + 1] += ids[at]); for (distinct = ids[at], at = cnt; at--; items[at] = ids[items[at]] - 1) orig[ids[items[at]] - 1] = items[at]; } unsigned max_length = 0xFFFFFFFFU, lengths[cnt]; memset(lengths, 0xFF, sizeof(lengths)); { int prefixes[distinct]; memset(prefixes, 0xFF, sizeof(prefixes)); for (at = cnt; at--; ) { for (others = items[at]; others; others &= others + 1) if ((int)lengths[at] < prefixes[--others]) lengths[at] = prefixes[others]; if (max_length == lengths[at]++) max_length++; for (others = items[at]; others < distinct && prefixes[others] < (int)lengths[at]; others |= others + 1 ) prefixes[others] = lengths[at]; } } unsigned order[cnt], indices[++max_length + 2]; memset(indices, 0, sizeof(indices)); for (at = cnt; at--; *(unsigned long *)&indices[lengths[at]] += 0x100000001UL); for (; ++at < (max_length >> 1); ((unsigned long *)indices)[at + 1] += ((unsigned long *)indices)[at]); for (at = 0; at < cnt; at++) order[--indices[lengths[at]]] = at; unsigned long suffix_counts[cnt]; unsigned successors[cnt]; { unsigned suffixes[distinct]; for (orig[(items[at] = distinct)] = 0xFFFFFFFFU; at & 1; successors[--at] = cnt); for (at >>= 1; at--; ((unsigned long *)successors)[at] = 0x100000001UL * cnt); for (at = distinct; at & 1; suffixes[--at] = cnt); for (at >>= 1; at--; ((unsigned long *)suffixes)[at] = 0x100000001UL * cnt) ; memset(suffix_counts, 0, sizeof(suffix_counts)); for (next = (tail = indices[(at += max_length)]); tail < indices[max_length]; suffix_counts[order[tail++]] = 1UL ); unsigned long sums[distinct]; for (memset(sums, 0, sizeof(sums)); at--; tail = indices[at + 1]) { while (indices[at] < next && indices[at + 1] < tail) if (order[tail - 1] < order[next - 1]) { if (suffix_counts[order[--tail]]) for (others = items[order[tail]] + 1; others; others &= others + 1) { if (items[order[tail]] < items[suffixes[--others]]) suffixes[others] = order[tail]; if (sums[others] > (0xFFFFFFFFFFFFFFFFUL ^ suffix_counts[order[tail]])) sums[others] = 0xFFFFFFFFFFFFFFFFUL; else sums[others] += suffix_counts[order[tail]]; } } else for (others = items[order[--next]] + 1; others < distinct; others |= others + 1) { if (items[suffixes[others]] < items[successors[order[next]]]) successors[order[next]] = suffixes[others]; if (suffix_counts[order[next]] > (0xFFFFFFFFFFFFFFFFUL ^ sums[others])) suffix_counts[order[next]] = 0xFFFFFFFFFFFFFFFFUL; else suffix_counts[order[next]] += sums[others]; } while (indices[at] < next) for (others = items[order[--next]] + 1; others < distinct; others |= others + 1) { if (items[suffixes[others]] < items[successors[order[next]]]) successors[order[next]] = suffixes[others]; if (suffix_counts[order[next]] > (0xFFFFFFFFFFFFFFFFUL ^ sums[others])) suffix_counts[order[next]] = 0xFFFFFFFFFFFFFFFFUL; else suffix_counts[order[next]] += sums[others]; } for (; tail < indices[at + 2]; tail++) if (suffix_counts[order[tail]]) for (others = items[order[tail]] + 1; others && sums[--others]; others &= others + 1 ) { sums[others] = 0; suffixes[others] = cnt; } } } for (others = 0; ++at < cnt; ) if (suffix_counts[order[at]]) { order[others++] = order[at]; indices[lengths[order[at]] + 1] = others; } unsigned *offsets = lengths; { unsigned largest_successor[order[0] + 1]; for (tail = (next = indices[at = (max_length - 1)]); tail < indices[max_length]; largest_successor[order[tail++]] = cnt) ; for (items[cnt] = 0; at--; tail = indices[at + 1]) { for (others = cnt; indices[at] < next && indices[at + 1] < tail; ) if (order[tail - 1] < order[next - 1]) { if (items[others] <= items[order[--tail]]) others = order[tail]; } else if (items[order[--next]] < items[others]) largest_successor[order[next]] = others; while (indices[at] < next) if (items[order[--next]] < items[others]) largest_successor[order[next]] = others; } items[cnt] = distinct; distinct = order[0] + 1; for (others = indices[(at = max_length)]; at--; ) for (descending_stbl( others - indices[at], &order[indices[at]], items, successors, largest_successor, offsets ); others > indices[at]; offsets[order[others]] = others ) --others; } unsigned freqs[distinct], solution[max_length + 1]; unsigned long prefix_factors[max_length + 1]; for (at = max_length; at--; prefix_factors[at] = 1UL); for (at = distinct; at & 1; freqs[--at] = 1); for (at >>= 1; at--; ((unsigned long *)freqs)[at] = 0x100000001UL); tail = 0xFFFFFFFFU; at = order[(indices[1] - 1)]; for (next = 0; next < max_length; at = successors[(tail = at)]) { for (others = offsets[(solution[next] = at)]; others-- > indices[next] && items[order[others]] == items[at] && successors[order[others]] == successors[at] && order[others] < tail; freqs[at]++ ); next++; prefix_factors[next] = sat_prod(prefix_factors[next], freqs[at]); if ((next | (next + 1)) < max_length) prefix_factors[next | (next + 1)] = sat_prod( prefix_factors[next], prefix_factors[next | (next + 1)] ); } unsigned long factors, total; unsigned base = 0; for ( ; ; ) { for (others = max_length - base; others; others >>= 1) { tail = (base + (others >> 1)); for (total = suffix_counts[solution[tail++]]; tail && total < rank; tail &= tail + 1 ) total = sat_prod(total, prefix_factors[--tail]); if (total >= rank) { base += (others >> (others != 1)); others += (others & (others != 1)); } } if (base == max_length) break ; for (factors = 1UL, tail = (at = base) + 1; tail; tail &= tail + 1) factors *= prefix_factors[--tail]; for (total = (factors * suffix_counts[solution[at]]); at < max_length && (factors * suffix_counts[solution[at]]) == total; factors *= freqs[solution[at++]] ); do for (others = offsets[solution[--at]]; indices[at] < others && at && solution[at - 1] < order[others - 1]; others--); while (at && others == indices[at]); if (others == 0) { solution[0] = cnt; max_length = 1; break ; } rank -= total; next = order[others - 1]; if (freqs[solution[at]] > 1) { freqs[next] = freqs[solution[at]] - 1; for (solution[at++] = next; at < max_length; at |= at + 1) { prefix_factors[at] /= (freqs[next] + 1); prefix_factors[at] *= freqs[next]; } } else for (; next != cnt; next = successors[next]) { tail = freqs[solution[at]]; for (others = offsets[next], freqs[next] = 1; others-- > indices[at] && items[order[others]] == items[next] && successors[order[others]] == successors[next]; freqs[next]++ ); if (tail != freqs[next]) for (others = at + 1; others < max_length; others |= others + 1) { prefix_factors[others] /= tail; prefix_factors[others] *= freqs[next]; } if (solution[at] == next) break ; solution[at++] = next; } } for (printf("%i", orig[items[solution[(at = 0)]]]); ++at < max_length; printf(" %u", orig[items[solution[at]]])); return 0; }

## Warmup

Implementation

Strings

Sorting

Search

Graph Theory

Greedy

Dynamic Programming

Constructive Algorithms

Bit Manipulation

Recursion

Game Theory

NP Complete

Debugging

## Leave a comment below