// tmp::Sort — C++14 TMP Introsort
// Phase 1: IntroSort (QuickSort + HeapSort fallback), skip small segments
// Phase 2: Single-pass Insertion Sort over whole array (guarded only)
// Correctness first, then optimization
#include <utility>
#include <type_traits>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
namespace tmp {
// ============================================================
// § 1 TMP 基礎工具
// ============================================================
template<int V> struct Int { static constexpr int value = V; };
template<bool V> struct Bool { static constexpr bool value = V; };
template<int N> struct Log2 : Int<1 + Log2<N/2>::value> {};
template<> struct Log2<1> : Int<0> {};
template<> struct Log2<0> : Int<0> {};
template<bool C, typename T, typename F> struct If { using type = F; };
template<typename T, typename F> struct If<true,T,F>{ using type = T; };
// ============================================================
// § 2 Comparator 策略
// ============================================================
template<typename T>
struct Less { bool operator()(const T& a, const T& b) const { return a < b; } };
template<typename T>
struct Greater { bool operator()(const T& a, const T& b) const { return a > b; } };
// ============================================================
// § 3 Median-of-3
// 排好 arr[lo] <= arr[mid] <= arr[hi],pivot(=arr[mid])放到 arr[hi-1]
// ============================================================
template<typename Comp>
struct MedianOf3 {
template<typename T>
static void apply(T* a, int lo, int mid, int hi, Comp cmp) {
if (cmp(a[mid], a[lo])) std::swap(a[mid], a[lo]);
if (cmp(a[hi], a[lo])) std::swap(a[hi], a[lo]);
if (cmp(a[hi], a[mid])) std::swap(a[hi], a[mid]);
std::swap(a[mid], a[hi-1]); // pivot → a[hi-1]
}
};
// ============================================================
// § 4 3-way Partition
// pivot 已在 a[hi-1];哨兵 a[lo]<=pivot, a[hi]>=pivot
// 結果:a[lt..gt]==pivot
// ============================================================
template<typename Comp>
struct Partition3Way {
template<typename T>
static std::pair<int,int> run(T* a, int lo, int hi, Comp cmp) {
T pivot = a[hi-1];
int lt = lo, gt = hi-1, i = lo;
while (i <= gt) {
if (cmp(a[i], pivot)) std::swap(a[lt++], a[i++]);
else if (cmp(pivot, a[i])) std::swap(a[i], a[gt--]);
else ++i;
}
return {lt, gt};
}
};
// ============================================================
// § 5 Heap Sort(depth 超標 fallback)
// ============================================================
template<typename Comp>
struct HeapSort {
template<typename T>
static void siftDown(T* a, int i, int n, int base, Comp cmp) {
T tmp = std::move(a[base+i]);
for (;;) {
int c = 2*i+1;
if (c >= n) break;
if (c+1 < n && cmp(a[base+c], a[base+c+1])) ++c;
if (!cmp(tmp, a[base+c])) break;
a[base+i] = std::move(a[base+c]);
i = c;
}
a[base+i] = std::move(tmp);
}
template<typename T>
static void sort(T* a, int lo, int hi, Comp cmp) {
int n = hi-lo+1;
for (int i = n/2-1; i >= 0; --i) siftDown(a, i, n, lo, cmp);
for (int i = n-1; i > 0; --i) {
std::swap(a[lo], a[lo+i]);
siftDown(a, 0, i, lo, cmp);
}
}
};
// ============================================================
// § 6 Insertion Sort(guarded,有邊界保護)
// ============================================================
template<typename Comp>
struct InsertionSort {
template<typename T>
static void sort(T* a, int lo, int hi, Comp cmp) {
for (int i = lo+1; i <= hi; ++i) {
T key = std::move(a[i]);
int j = i-1;
while (j >= lo && cmp(key, a[j])) {
a[j+1] = std::move(a[j]); --j;
}
a[j+1] = std::move(key);
}
}
};
// ============================================================
// § 7 IntroSort 核心
// ============================================================
template<typename Comp, int THRESHOLD>
struct IntroCore {
template<typename T>
static void sort(T* a, int lo, int hi, int depth, Comp cmp) {
while (hi - lo + 1 > THRESHOLD) {
if (depth == 0) {
HeapSort<Comp>::sort(a, lo, hi, cmp);
return;
}
--depth;
int mid = lo + (hi-lo)/2;
MedianOf3<Comp>::apply(a, lo, mid, hi, cmp);
auto p = Partition3Way<Comp>::run(a, lo, hi, cmp);
// 尾遞迴:遞迴較小側
if (p.first - lo < hi - p.second) {
sort(a, lo, p.first-1, depth, cmp);
lo = p.second + 1;
} else {
sort(a, p.second+1, hi, depth, cmp);
hi = p.first - 1;
}
}
// 小段落下給 Phase 2
}
};
// ============================================================
// § 8 對外介面:tmp::Sort<THRESHOLD>
// ============================================================
template<int THRESHOLD = 16>
struct Sort {
static int depthLimit(int n) {
int d = 0; while (n > 1) { n >>= 1; ++d; } return d * 2;
}
// --- sort(arr, n) ---
template<typename T>
static void sort(T* a, int n) { sort(a, n, Less<T>{}); }
// --- sort(arr, n, comp) ---
template<typename T, typename Comp>
static void sort(T* a, int n, Comp cmp) {
if (n <= 1) return;
using Core = IntroCore<Comp, THRESHOLD>;
// Phase 1:QuickSort,跳過小片段
Core::sort(a, 0, n-1, depthLimit(n), cmp);
// Phase 2:一次 Insertion Sort 收尾(guarded,正確且簡單)
InsertionSort<Comp>::sort(a, 0, n-1, cmp);
}
// --- sort(first, last) ---
template<typename T>
static void sort(T* first, T* last) {
sort(first, static_cast<int>(last - first));
}
// --- sort(first, last, comp) ---
template<typename T, typename Comp>
static void sort(T* first, T* last, Comp cmp) {
sort(first, static_cast<int>(last - first), cmp);
}
};
} // namespace tmp
// ============================================================
// § 9 Demo
// ============================================================
static bool verify(const int* a, const int* b, int n) {
for (int i = 0; i < n; ++i) if (a[i] != b[i]) return false;
return true;
}
static void test(const char* name, int* a, int* r, int n) {
std::sort(r, r+n);
tmp::Sort<>::sort(a, n);
printf("[%s] n=%-8d %s\n", verify(a,r,n)?"PASS":"FAIL", n, name);
}
static void show(const char* lbl, const int* a, int n) {
printf(" %-30s", lbl);
int s = n<20?n:20;
for(int i=0;i<s;i++) printf("%d%c",a[i]," \n"[i==s-1]);
if(n>20) printf(" ...(n=%d)\n",n);
}
int main() {
srand(42);
printf("=== tmp::Sort<> — Introsort TMP ===\n\n");
// 1. 基本
{ int a[]={5,3,8,1,9,2,7,4,6,0},r[]={5,3,8,1,9,2,7,4,6,0};
test("random 10",a,r,10); show("→",a,10); }
// 2. 邊界:n=0,1,2
{ int a1[]={}, r1[]={}; test("n=0",a1,r1,0); }
{ int a2[]={7}, r2[]={7}; test("n=1",a2,r2,1); }
{ int a3[]={5,2}, r3[]={5,2}; test("n=2",a3,r3,2); }
// 3. 已排序 升/降
{ static int a[10000],r[10000];
for(int i=0;i<10000;i++) a[i]=r[i]=i;
test("sorted asc 10000",a,r,10000);
for(int i=0;i<10000;i++) a[i]=r[i]=9999-i;
test("sorted desc 10000",a,r,10000); }
// 4. 全部相同
{ static int a[100000],r[100000];
for(int i=0;i<100000;i++) a[i]=r[i]=42;
test("all equal 100000",a,r,100000); }
// 5. 大量重複(3-way partition 優勢)
{ static int a[100000],r[100000];
for(int i=0;i<100000;i++) a[i]=r[i]=rand()%100;
test("100 vals in 100000",a,r,100000); }
// 6. 大陣列隨機
{ static int a[1000000],r[1000000];
for(int i=0;i<1000000;i++) a[i]=r[i]=rand();
test("random 1000000",a,r,1000000); }
// 7. 自訂 Comp(降序)
printf("\n--- Descending ---\n");
{ int a[]={3,1,4,1,5,9,2,6,5,3};
tmp::Sort<>::sort(a,10,tmp::Greater<int>{});
show("desc:",a,10); }
// 8. 指標範圍介面
printf("--- Pointer range ---\n");
{ int a[]={9,1,8,2,7,3,6,4,5,0};
tmp::Sort<>::sort(a,a+10);
show("range:",a,10); }
// 9. 自訂 struct + lambda
printf("--- Struct + lambda ---\n");
{ struct Pt { int x,y; };
Pt pts[]={{3,1},{1,5},{2,2},{1,1},{3,0}};
tmp::Sort<>::sort(pts,5,[](const Pt&a,const Pt&b){
return a.x!=b.x?a.x<b.x:a.y<b.y; });
for(int i=0;i<5;i++) printf("(%d,%d)%c",pts[i].x,pts[i].y," \n"[i==4]); }
// 10. 不同 THRESHOLD
printf("--- THRESHOLD=4 ---\n");
{ static int a[50000],r[50000];
for(int i=0;i<50000;i++) a[i]=r[i]=rand();
std::sort(r,r+50000);
tmp::Sort<4>::sort(a,50000);
printf("[%s] THRESHOLD=4 n=50000\n",verify(a,r,50000)?"PASS":"FAIL"); }
// 11. 互動
printf("\n--- Interactive ---\n");
{ int n; scanf("%d",&n);
static int a[1000000];
for(int i=0;i<n;i++) scanf("%d",&a[i]);
tmp::Sort<>::sort(a,n);
for(int i=0;i<n;i++) printf("%d%c",a[i]," \n"[i==n-1]); }
return 0;
}
Ly8gdG1wOjpTb3J0IOKAlCBDKysxNCBUTVAgSW50cm9zb3J0Ci8vIFBoYXNlIDE6IEludHJvU29ydCAoUXVpY2tTb3J0ICsgSGVhcFNvcnQgZmFsbGJhY2spLCBza2lwIHNtYWxsIHNlZ21lbnRzCi8vIFBoYXNlIDI6IFNpbmdsZS1wYXNzIEluc2VydGlvbiBTb3J0IG92ZXIgd2hvbGUgYXJyYXkgKGd1YXJkZWQgb25seSkKLy8gQ29ycmVjdG5lc3MgZmlyc3QsIHRoZW4gb3B0aW1pemF0aW9uCgojaW5jbHVkZSA8dXRpbGl0eT4KI2luY2x1ZGUgPHR5cGVfdHJhaXRzPgojaW5jbHVkZSA8Y3N0ZGlvPgojaW5jbHVkZSA8Y3N0ZGxpYj4KI2luY2x1ZGUgPGFsZ29yaXRobT4KCm5hbWVzcGFjZSB0bXAgewoKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ci8vIMKnIDEgIFRNUCDln7rnpI7lt6XlhbcKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRlbXBsYXRlPGludCBWPiAgc3RydWN0IEludCAgeyBzdGF0aWMgY29uc3RleHByIGludCAgdmFsdWUgPSBWOyB9Owp0ZW1wbGF0ZTxib29sIFY+IHN0cnVjdCBCb29sIHsgc3RhdGljIGNvbnN0ZXhwciBib29sIHZhbHVlID0gVjsgfTsKCnRlbXBsYXRlPGludCBOPiBzdHJ1Y3QgTG9nMiA6IEludDwxICsgTG9nMjxOLzI+Ojp2YWx1ZT4ge307CnRlbXBsYXRlPD4gICAgICBzdHJ1Y3QgTG9nMjwxPiA6IEludDwwPiB7fTsKdGVtcGxhdGU8PiAgICAgIHN0cnVjdCBMb2cyPDA+IDogSW50PDA+IHt9OwoKdGVtcGxhdGU8Ym9vbCBDLCB0eXBlbmFtZSBULCB0eXBlbmFtZSBGPiBzdHJ1Y3QgSWYgICAgICAgICAgeyB1c2luZyB0eXBlID0gRjsgfTsKdGVtcGxhdGU8dHlwZW5hbWUgVCwgdHlwZW5hbWUgRj4gICAgICAgICBzdHJ1Y3QgSWY8dHJ1ZSxULEY+eyB1c2luZyB0eXBlID0gVDsgfTsKCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyDCpyAyICBDb21wYXJhdG9yIOetlueVpQovLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KdGVtcGxhdGU8dHlwZW5hbWUgVD4Kc3RydWN0IExlc3MgICAgeyBib29sIG9wZXJhdG9yKCkoY29uc3QgVCYgYSwgY29uc3QgVCYgYikgY29uc3QgeyByZXR1cm4gYSA8IGI7IH0gfTsKdGVtcGxhdGU8dHlwZW5hbWUgVD4Kc3RydWN0IEdyZWF0ZXIgeyBib29sIG9wZXJhdG9yKCkoY29uc3QgVCYgYSwgY29uc3QgVCYgYikgY29uc3QgeyByZXR1cm4gYSA+IGI7IH0gfTsKCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyDCpyAzICBNZWRpYW4tb2YtMwovLyAgICDmjpLlpb0gYXJyW2xvXSA8PSBhcnJbbWlkXSA8PSBhcnJbaGld77yMcGl2b3QoPWFyclttaWRdKeaUvuWIsCBhcnJbaGktMV0KLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRlbXBsYXRlPHR5cGVuYW1lIENvbXA+CnN0cnVjdCBNZWRpYW5PZjMgewogICAgdGVtcGxhdGU8dHlwZW5hbWUgVD4KICAgIHN0YXRpYyB2b2lkIGFwcGx5KFQqIGEsIGludCBsbywgaW50IG1pZCwgaW50IGhpLCBDb21wIGNtcCkgewogICAgICAgIGlmIChjbXAoYVttaWRdLCBhW2xvXSkpICBzdGQ6OnN3YXAoYVttaWRdLCBhW2xvXSk7CiAgICAgICAgaWYgKGNtcChhW2hpXSwgIGFbbG9dKSkgIHN0ZDo6c3dhcChhW2hpXSwgIGFbbG9dKTsKICAgICAgICBpZiAoY21wKGFbaGldLCAgYVttaWRdKSkgc3RkOjpzd2FwKGFbaGldLCAgYVttaWRdKTsKICAgICAgICBzdGQ6OnN3YXAoYVttaWRdLCBhW2hpLTFdKTsgICAvLyBwaXZvdCDihpIgYVtoaS0xXQogICAgfQp9OwoKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ci8vIMKnIDQgIDMtd2F5IFBhcnRpdGlvbgovLyAgICBwaXZvdCDlt7LlnKggYVtoaS0xXe+8m+WTqOWFtSBhW2xvXTw9cGl2b3QsIGFbaGldPj1waXZvdAovLyAgICDntZDmnpzvvJphW2x0Li5ndF09PXBpdm90Ci8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQp0ZW1wbGF0ZTx0eXBlbmFtZSBDb21wPgpzdHJ1Y3QgUGFydGl0aW9uM1dheSB7CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBUPgogICAgc3RhdGljIHN0ZDo6cGFpcjxpbnQsaW50PiBydW4oVCogYSwgaW50IGxvLCBpbnQgaGksIENvbXAgY21wKSB7CiAgICAgICAgVCBwaXZvdCA9IGFbaGktMV07CiAgICAgICAgaW50IGx0ID0gbG8sIGd0ID0gaGktMSwgaSA9IGxvOwogICAgICAgIHdoaWxlIChpIDw9IGd0KSB7CiAgICAgICAgICAgIGlmICAgICAgKGNtcChhW2ldLCBwaXZvdCkpIHN0ZDo6c3dhcChhW2x0KytdLCBhW2krK10pOwogICAgICAgICAgICBlbHNlIGlmIChjbXAocGl2b3QsIGFbaV0pKSBzdGQ6OnN3YXAoYVtpXSwgICAgYVtndC0tXSk7CiAgICAgICAgICAgIGVsc2UgICAgICAgICAgICAgICAgICAgICAgICsraTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHtsdCwgZ3R9OwogICAgfQp9OwoKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ci8vIMKnIDUgIEhlYXAgU29ydO+8iGRlcHRoIOi2heaomSBmYWxsYmFja++8iQovLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KdGVtcGxhdGU8dHlwZW5hbWUgQ29tcD4Kc3RydWN0IEhlYXBTb3J0IHsKICAgIHRlbXBsYXRlPHR5cGVuYW1lIFQ+CiAgICBzdGF0aWMgdm9pZCBzaWZ0RG93bihUKiBhLCBpbnQgaSwgaW50IG4sIGludCBiYXNlLCBDb21wIGNtcCkgewogICAgICAgIFQgdG1wID0gc3RkOjptb3ZlKGFbYmFzZStpXSk7CiAgICAgICAgZm9yICg7OykgewogICAgICAgICAgICBpbnQgYyA9IDIqaSsxOwogICAgICAgICAgICBpZiAoYyA+PSBuKSBicmVhazsKICAgICAgICAgICAgaWYgKGMrMSA8IG4gJiYgY21wKGFbYmFzZStjXSwgYVtiYXNlK2MrMV0pKSArK2M7CiAgICAgICAgICAgIGlmICghY21wKHRtcCwgYVtiYXNlK2NdKSkgYnJlYWs7CiAgICAgICAgICAgIGFbYmFzZStpXSA9IHN0ZDo6bW92ZShhW2Jhc2UrY10pOwogICAgICAgICAgICBpID0gYzsKICAgICAgICB9CiAgICAgICAgYVtiYXNlK2ldID0gc3RkOjptb3ZlKHRtcCk7CiAgICB9CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBUPgogICAgc3RhdGljIHZvaWQgc29ydChUKiBhLCBpbnQgbG8sIGludCBoaSwgQ29tcCBjbXApIHsKICAgICAgICBpbnQgbiA9IGhpLWxvKzE7CiAgICAgICAgZm9yIChpbnQgaSA9IG4vMi0xOyBpID49IDA7IC0taSkgc2lmdERvd24oYSwgaSwgbiwgbG8sIGNtcCk7CiAgICAgICAgZm9yIChpbnQgaSA9IG4tMTsgICBpID4gMDsgIC0taSkgewogICAgICAgICAgICBzdGQ6OnN3YXAoYVtsb10sIGFbbG8raV0pOwogICAgICAgICAgICBzaWZ0RG93bihhLCAwLCBpLCBsbywgY21wKTsKICAgICAgICB9CiAgICB9Cn07CgovLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLy8gwqcgNiAgSW5zZXJ0aW9uIFNvcnTvvIhndWFyZGVk77yM5pyJ6YKK55WM5L+d6K2377yJCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQp0ZW1wbGF0ZTx0eXBlbmFtZSBDb21wPgpzdHJ1Y3QgSW5zZXJ0aW9uU29ydCB7CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBUPgogICAgc3RhdGljIHZvaWQgc29ydChUKiBhLCBpbnQgbG8sIGludCBoaSwgQ29tcCBjbXApIHsKICAgICAgICBmb3IgKGludCBpID0gbG8rMTsgaSA8PSBoaTsgKytpKSB7CiAgICAgICAgICAgIFQga2V5ID0gc3RkOjptb3ZlKGFbaV0pOwogICAgICAgICAgICBpbnQgaiA9IGktMTsKICAgICAgICAgICAgd2hpbGUgKGogPj0gbG8gJiYgY21wKGtleSwgYVtqXSkpIHsKICAgICAgICAgICAgICAgIGFbaisxXSA9IHN0ZDo6bW92ZShhW2pdKTsgLS1qOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGFbaisxXSA9IHN0ZDo6bW92ZShrZXkpOwogICAgICAgIH0KICAgIH0KfTsKCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyDCpyA3ICBJbnRyb1NvcnQg5qC45b+DCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQp0ZW1wbGF0ZTx0eXBlbmFtZSBDb21wLCBpbnQgVEhSRVNIT0xEPgpzdHJ1Y3QgSW50cm9Db3JlIHsKICAgIHRlbXBsYXRlPHR5cGVuYW1lIFQ+CiAgICBzdGF0aWMgdm9pZCBzb3J0KFQqIGEsIGludCBsbywgaW50IGhpLCBpbnQgZGVwdGgsIENvbXAgY21wKSB7CiAgICAgICAgd2hpbGUgKGhpIC0gbG8gKyAxID4gVEhSRVNIT0xEKSB7CiAgICAgICAgICAgIGlmIChkZXB0aCA9PSAwKSB7CiAgICAgICAgICAgICAgICBIZWFwU29ydDxDb21wPjo6c29ydChhLCBsbywgaGksIGNtcCk7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLS1kZXB0aDsKICAgICAgICAgICAgaW50IG1pZCA9IGxvICsgKGhpLWxvKS8yOwogICAgICAgICAgICBNZWRpYW5PZjM8Q29tcD46OmFwcGx5KGEsIGxvLCBtaWQsIGhpLCBjbXApOwogICAgICAgICAgICBhdXRvIHAgPSBQYXJ0aXRpb24zV2F5PENvbXA+OjpydW4oYSwgbG8sIGhpLCBjbXApOwogICAgICAgICAgICAvLyDlsL7pgZ7ov7TvvJrpgZ7ov7TovIPlsI/lgbQKICAgICAgICAgICAgaWYgKHAuZmlyc3QgLSBsbyA8IGhpIC0gcC5zZWNvbmQpIHsKICAgICAgICAgICAgICAgIHNvcnQoYSwgbG8sICAgICAgICAgIHAuZmlyc3QtMSwgIGRlcHRoLCBjbXApOwogICAgICAgICAgICAgICAgbG8gPSBwLnNlY29uZCArIDE7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBzb3J0KGEsIHAuc2Vjb25kKzEsIGhpLCAgICAgICAgICAgZGVwdGgsIGNtcCk7CiAgICAgICAgICAgICAgICBoaSA9IHAuZmlyc3QgLSAxOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8vIOWwj+auteiQveS4i+e1piBQaGFzZSAyCiAgICB9Cn07CgovLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLy8gwqcgOCAg5bCN5aSW5LuL6Z2i77yadG1wOjpTb3J0PFRIUkVTSE9MRD4KLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRlbXBsYXRlPGludCBUSFJFU0hPTEQgPSAxNj4Kc3RydWN0IFNvcnQgewogICAgc3RhdGljIGludCBkZXB0aExpbWl0KGludCBuKSB7CiAgICAgICAgaW50IGQgPSAwOyB3aGlsZSAobiA+IDEpIHsgbiA+Pj0gMTsgKytkOyB9IHJldHVybiBkICogMjsKICAgIH0KCiAgICAvLyAtLS0gc29ydChhcnIsIG4pIC0tLQogICAgdGVtcGxhdGU8dHlwZW5hbWUgVD4KICAgIHN0YXRpYyB2b2lkIHNvcnQoVCogYSwgaW50IG4pIHsgc29ydChhLCBuLCBMZXNzPFQ+e30pOyB9CgogICAgLy8gLS0tIHNvcnQoYXJyLCBuLCBjb21wKSAtLS0KICAgIHRlbXBsYXRlPHR5cGVuYW1lIFQsIHR5cGVuYW1lIENvbXA+CiAgICBzdGF0aWMgdm9pZCBzb3J0KFQqIGEsIGludCBuLCBDb21wIGNtcCkgewogICAgICAgIGlmIChuIDw9IDEpIHJldHVybjsKICAgICAgICB1c2luZyBDb3JlID0gSW50cm9Db3JlPENvbXAsIFRIUkVTSE9MRD47CiAgICAgICAgLy8gUGhhc2UgMe+8mlF1aWNrU29ydO+8jOi3s+mBjuWwj+eJh+autQogICAgICAgIENvcmU6OnNvcnQoYSwgMCwgbi0xLCBkZXB0aExpbWl0KG4pLCBjbXApOwogICAgICAgIC8vIFBoYXNlIDLvvJrkuIDmrKEgSW5zZXJ0aW9uIFNvcnQg5pS25bC+77yIZ3VhcmRlZO+8jOato+eiuuS4lOewoeWWru+8iQogICAgICAgIEluc2VydGlvblNvcnQ8Q29tcD46OnNvcnQoYSwgMCwgbi0xLCBjbXApOwogICAgfQoKICAgIC8vIC0tLSBzb3J0KGZpcnN0LCBsYXN0KSAtLS0KICAgIHRlbXBsYXRlPHR5cGVuYW1lIFQ+CiAgICBzdGF0aWMgdm9pZCBzb3J0KFQqIGZpcnN0LCBUKiBsYXN0KSB7CiAgICAgICAgc29ydChmaXJzdCwgc3RhdGljX2Nhc3Q8aW50PihsYXN0IC0gZmlyc3QpKTsKICAgIH0KCiAgICAvLyAtLS0gc29ydChmaXJzdCwgbGFzdCwgY29tcCkgLS0tCiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZSBDb21wPgogICAgc3RhdGljIHZvaWQgc29ydChUKiBmaXJzdCwgVCogbGFzdCwgQ29tcCBjbXApIHsKICAgICAgICBzb3J0KGZpcnN0LCBzdGF0aWNfY2FzdDxpbnQ+KGxhc3QgLSBmaXJzdCksIGNtcCk7CiAgICB9Cn07Cgp9IC8vIG5hbWVzcGFjZSB0bXAKCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyDCpyA5ICBEZW1vCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpzdGF0aWMgYm9vbCB2ZXJpZnkoY29uc3QgaW50KiBhLCBjb25zdCBpbnQqIGIsIGludCBuKSB7CiAgICBmb3IgKGludCBpID0gMDsgaSA8IG47ICsraSkgaWYgKGFbaV0gIT0gYltpXSkgcmV0dXJuIGZhbHNlOwogICAgcmV0dXJuIHRydWU7Cn0Kc3RhdGljIHZvaWQgdGVzdChjb25zdCBjaGFyKiBuYW1lLCBpbnQqIGEsIGludCogciwgaW50IG4pIHsKICAgIHN0ZDo6c29ydChyLCByK24pOwogICAgdG1wOjpTb3J0PD46OnNvcnQoYSwgbik7CiAgICBwcmludGYoIlslc10gbj0lLThkICAlc1xuIiwgdmVyaWZ5KGEscixuKT8iUEFTUyI6IkZBSUwiLCBuLCBuYW1lKTsKfQpzdGF0aWMgdm9pZCBzaG93KGNvbnN0IGNoYXIqIGxibCwgY29uc3QgaW50KiBhLCBpbnQgbikgewogICAgcHJpbnRmKCIgICUtMzBzIiwgbGJsKTsKICAgIGludCBzID0gbjwyMD9uOjIwOwogICAgZm9yKGludCBpPTA7aTxzO2krKykgcHJpbnRmKCIlZCVjIixhW2ldLCIgXG4iW2k9PXMtMV0pOwogICAgaWYobj4yMCkgcHJpbnRmKCIgLi4uKG49JWQpXG4iLG4pOwp9CgppbnQgbWFpbigpIHsKICAgIHNyYW5kKDQyKTsKICAgIHByaW50ZigiPT09IHRtcDo6U29ydDw+IOKAlCBJbnRyb3NvcnQgVE1QID09PVxuXG4iKTsKCiAgICAvLyAxLiDln7rmnKwKICAgIHsgaW50IGFbXT17NSwzLDgsMSw5LDIsNyw0LDYsMH0scltdPXs1LDMsOCwxLDksMiw3LDQsNiwwfTsKICAgICAgdGVzdCgicmFuZG9tIDEwIixhLHIsMTApOyBzaG93KCLihpIiLGEsMTApOyB9CgogICAgLy8gMi4g6YKK55WM77yabj0wLDEsMgogICAgeyBpbnQgYTFbXT17fSwgcjFbXT17fTsgICAgICAgICAgdGVzdCgibj0wIixhMSxyMSwwKTsgfQogICAgeyBpbnQgYTJbXT17N30sIHIyW109ezd9OyAgICAgICAgdGVzdCgibj0xIixhMixyMiwxKTsgfQogICAgeyBpbnQgYTNbXT17NSwyfSwgcjNbXT17NSwyfTsgICAgdGVzdCgibj0yIixhMyxyMywyKTsgfQoKICAgIC8vIDMuIOW3suaOkuW6jyDljYcv6ZmNCiAgICB7IHN0YXRpYyBpbnQgYVsxMDAwMF0sclsxMDAwMF07CiAgICAgIGZvcihpbnQgaT0wO2k8MTAwMDA7aSsrKSBhW2ldPXJbaV09aTsKICAgICAgdGVzdCgic29ydGVkIGFzYyAxMDAwMCIsYSxyLDEwMDAwKTsKICAgICAgZm9yKGludCBpPTA7aTwxMDAwMDtpKyspIGFbaV09cltpXT05OTk5LWk7CiAgICAgIHRlc3QoInNvcnRlZCBkZXNjIDEwMDAwIixhLHIsMTAwMDApOyB9CgogICAgLy8gNC4g5YWo6YOo55u45ZCMCiAgICB7IHN0YXRpYyBpbnQgYVsxMDAwMDBdLHJbMTAwMDAwXTsKICAgICAgZm9yKGludCBpPTA7aTwxMDAwMDA7aSsrKSBhW2ldPXJbaV09NDI7CiAgICAgIHRlc3QoImFsbCBlcXVhbCAxMDAwMDAiLGEsciwxMDAwMDApOyB9CgogICAgLy8gNS4g5aSn6YeP6YeN6KSH77yIMy13YXkgcGFydGl0aW9uIOWEquWLou+8iQogICAgeyBzdGF0aWMgaW50IGFbMTAwMDAwXSxyWzEwMDAwMF07CiAgICAgIGZvcihpbnQgaT0wO2k8MTAwMDAwO2krKykgYVtpXT1yW2ldPXJhbmQoKSUxMDA7CiAgICAgIHRlc3QoIjEwMCB2YWxzIGluIDEwMDAwMCIsYSxyLDEwMDAwMCk7IH0KCiAgICAvLyA2LiDlpKfpmaPliJfpmqjmqZ8KICAgIHsgc3RhdGljIGludCBhWzEwMDAwMDBdLHJbMTAwMDAwMF07CiAgICAgIGZvcihpbnQgaT0wO2k8MTAwMDAwMDtpKyspIGFbaV09cltpXT1yYW5kKCk7CiAgICAgIHRlc3QoInJhbmRvbSAxMDAwMDAwIixhLHIsMTAwMDAwMCk7IH0KCiAgICAvLyA3LiDoh6roqIIgQ29tcO+8iOmZjeW6j++8iQogICAgcHJpbnRmKCJcbi0tLSBEZXNjZW5kaW5nIC0tLVxuIik7CiAgICB7IGludCBhW109ezMsMSw0LDEsNSw5LDIsNiw1LDN9OwogICAgICB0bXA6OlNvcnQ8Pjo6c29ydChhLDEwLHRtcDo6R3JlYXRlcjxpbnQ+e30pOwogICAgICBzaG93KCJkZXNjOiIsYSwxMCk7IH0KCiAgICAvLyA4LiDmjIfmqJnnr4TlnI3ku4vpnaIKICAgIHByaW50ZigiLS0tIFBvaW50ZXIgcmFuZ2UgLS0tXG4iKTsKICAgIHsgaW50IGFbXT17OSwxLDgsMiw3LDMsNiw0LDUsMH07CiAgICAgIHRtcDo6U29ydDw+Ojpzb3J0KGEsYSsxMCk7CiAgICAgIHNob3coInJhbmdlOiIsYSwxMCk7IH0KCiAgICAvLyA5LiDoh6roqIIgc3RydWN0ICsgbGFtYmRhCiAgICBwcmludGYoIi0tLSBTdHJ1Y3QgKyBsYW1iZGEgLS0tXG4iKTsKICAgIHsgc3RydWN0IFB0IHsgaW50IHgseTsgfTsKICAgICAgUHQgcHRzW109e3szLDF9LHsxLDV9LHsyLDJ9LHsxLDF9LHszLDB9fTsKICAgICAgdG1wOjpTb3J0PD46OnNvcnQocHRzLDUsW10oY29uc3QgUHQmYSxjb25zdCBQdCZiKXsKICAgICAgICAgIHJldHVybiBhLnghPWIueD9hLng8Yi54OmEueTxiLnk7IH0pOwogICAgICBmb3IoaW50IGk9MDtpPDU7aSsrKSBwcmludGYoIiglZCwlZCklYyIscHRzW2ldLngscHRzW2ldLnksIiBcbiJbaT09NF0pOyB9CgogICAgLy8gMTAuIOS4jeWQjCBUSFJFU0hPTEQKICAgIHByaW50ZigiLS0tIFRIUkVTSE9MRD00IC0tLVxuIik7CiAgICB7IHN0YXRpYyBpbnQgYVs1MDAwMF0scls1MDAwMF07CiAgICAgIGZvcihpbnQgaT0wO2k8NTAwMDA7aSsrKSBhW2ldPXJbaV09cmFuZCgpOwogICAgICBzdGQ6OnNvcnQocixyKzUwMDAwKTsKICAgICAgdG1wOjpTb3J0PDQ+Ojpzb3J0KGEsNTAwMDApOwogICAgICBwcmludGYoIlslc10gVEhSRVNIT0xEPTQgbj01MDAwMFxuIix2ZXJpZnkoYSxyLDUwMDAwKT8iUEFTUyI6IkZBSUwiKTsgfQoKICAgIC8vIDExLiDkupLli5UKICAgIHByaW50ZigiXG4tLS0gSW50ZXJhY3RpdmUgLS0tXG4iKTsKICAgIHsgaW50IG47IHNjYW5mKCIlZCIsJm4pOwogICAgICBzdGF0aWMgaW50IGFbMTAwMDAwMF07CiAgICAgIGZvcihpbnQgaT0wO2k8bjtpKyspIHNjYW5mKCIlZCIsJmFbaV0pOwogICAgICB0bXA6OlNvcnQ8Pjo6c29ydChhLG4pOwogICAgICBmb3IoaW50IGk9MDtpPG47aSsrKSBwcmludGYoIiVkJWMiLGFbaV0sIiBcbiJbaT09bi0xXSk7IH0KCiAgICByZXR1cm4gMDsKfQ==