#include <iostream>
#include <random>
#include <algorithm>
#include <numeric>
#include <vector>
using namespace std;
using U = uint_fast32_t;
using VU = vector<U>;
using ULA = uint_fast64_t;
enum {
kLookaheadSize = 64,
};
bool cycleRO(const VU& permutation, size_t i_start, size_t& cnt)
{
if (i_start == 0)
return true;
auto index = i_start;
do {
index = permutation[index];
++cnt;
if (index < i_start)
return false;
} while (index != i_start);
return true;
}
void cycleRW(VU& permutation, size_t i_start, ULA& lookahead)
{
auto index = i_start;
auto next_ind = permutation[index];
do {
const auto value = permutation[next_ind];
permutation[next_ind] = index;
index = next_ind;
next_ind = value;
const auto lookahead_pos = index - i_start;
if (lookahead_pos < kLookaheadSize)
lookahead |= 1ull << lookahead_pos;
} while (index != i_start);
}
size_t invert(VU& permutation)
{
size_t cnt = 0;
const auto n = permutation.size();
ULA lookahead = 0;
for (size_t i_start = 0; i_start != n - 1; ++i_start)
{
lookahead >>= 1;
if (!(lookahead&1) && cycleRO(permutation, i_start, cnt))
cycleRW(permutation, i_start, lookahead);
}
return cnt;
}
int main()
{
random_device rd;
mt19937_64 rng(rd());
for (size_t exp = 0; exp <= 20; ++exp)
{
const auto n = 1ull << exp;
VU permutation(n);
iota(begin(permutation), end(permutation), 0);
shuffle(begin(permutation), end(permutation), rng);
VU second_copy(permutation);
const auto cnt = invert(permutation);
cout << exp << ' ' << (double)cnt / n << '\n';
invert(permutation);
if (permutation != second_copy)
{
cout << "Wrong result\n";
return 0;
}
}
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8cmFuZG9tPgojaW5jbHVkZSA8YWxnb3JpdGhtPgojaW5jbHVkZSA8bnVtZXJpYz4KI2luY2x1ZGUgPHZlY3Rvcj4KCnVzaW5nIG5hbWVzcGFjZSBzdGQ7CnVzaW5nIFUgPSB1aW50X2Zhc3QzMl90Owp1c2luZyBWVSA9IHZlY3RvcjxVPjsKdXNpbmcgVUxBID0gdWludF9mYXN0NjRfdDsKCmVudW0gewogICAga0xvb2thaGVhZFNpemUgPSA2NCwKfTsKCmJvb2wgY3ljbGVSTyhjb25zdCBWVSYgcGVybXV0YXRpb24sIHNpemVfdCBpX3N0YXJ0LCBzaXplX3QmIGNudCkKewogICAgaWYgKGlfc3RhcnQgPT0gMCkKICAgICAgICByZXR1cm4gdHJ1ZTsKCiAgICBhdXRvIGluZGV4ID0gaV9zdGFydDsKICAgIGRvIHsKICAgICAgICBpbmRleCA9IHBlcm11dGF0aW9uW2luZGV4XTsKICAgICAgICArK2NudDsKCiAgICAgICAgaWYgKGluZGV4IDwgaV9zdGFydCkKICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwoKICAgIH0gd2hpbGUgKGluZGV4ICE9IGlfc3RhcnQpOwoKICAgIHJldHVybiB0cnVlOwp9Cgp2b2lkIGN5Y2xlUlcoVlUmIHBlcm11dGF0aW9uLCBzaXplX3QgaV9zdGFydCwgVUxBJiBsb29rYWhlYWQpCnsKICAgIGF1dG8gaW5kZXggPSBpX3N0YXJ0OwogICAgYXV0byBuZXh0X2luZCA9IHBlcm11dGF0aW9uW2luZGV4XTsKCiAgICBkbyB7CiAgICAgICAgY29uc3QgYXV0byB2YWx1ZSA9IHBlcm11dGF0aW9uW25leHRfaW5kXTsKICAgICAgICBwZXJtdXRhdGlvbltuZXh0X2luZF0gPSBpbmRleDsKICAgICAgICBpbmRleCA9IG5leHRfaW5kOwogICAgICAgIG5leHRfaW5kID0gdmFsdWU7CiAgICAgICAgY29uc3QgYXV0byBsb29rYWhlYWRfcG9zID0gaW5kZXggLSBpX3N0YXJ0OwoKICAgICAgICBpZiAobG9va2FoZWFkX3BvcyA8IGtMb29rYWhlYWRTaXplKQogICAgICAgICAgICBsb29rYWhlYWQgfD0gMXVsbCA8PCBsb29rYWhlYWRfcG9zOwoKICAgIH0gd2hpbGUgKGluZGV4ICE9IGlfc3RhcnQpOwp9CgpzaXplX3QgaW52ZXJ0KFZVJiBwZXJtdXRhdGlvbikKewogICAgc2l6ZV90IGNudCA9IDA7CiAgICBjb25zdCBhdXRvIG4gPSBwZXJtdXRhdGlvbi5zaXplKCk7CiAgICBVTEEgbG9va2FoZWFkID0gMDsKCiAgICBmb3IgKHNpemVfdCBpX3N0YXJ0ID0gMDsgaV9zdGFydCAhPSBuIC0gMTsgKytpX3N0YXJ0KQogICAgewogICAgICAgIGxvb2thaGVhZCA+Pj0gMTsKCiAgICAgICAgaWYgKCEobG9va2FoZWFkJjEpICYmIGN5Y2xlUk8ocGVybXV0YXRpb24sIGlfc3RhcnQsIGNudCkpCiAgICAgICAgICAgIGN5Y2xlUlcocGVybXV0YXRpb24sIGlfc3RhcnQsIGxvb2thaGVhZCk7CiAgICB9CgogICAgcmV0dXJuIGNudDsKfQoKaW50IG1haW4oKQp7CiAgICByYW5kb21fZGV2aWNlIHJkOwogICAgbXQxOTkzN182NCBybmcocmQoKSk7CgogICAgZm9yIChzaXplX3QgZXhwID0gMDsgZXhwIDw9IDIwOyArK2V4cCkKICAgIHsKICAgICAgICBjb25zdCBhdXRvIG4gPSAxdWxsIDw8IGV4cDsKICAgICAgICBWVSBwZXJtdXRhdGlvbihuKTsKICAgICAgICBpb3RhKGJlZ2luKHBlcm11dGF0aW9uKSwgZW5kKHBlcm11dGF0aW9uKSwgMCk7CiAgICAgICAgc2h1ZmZsZShiZWdpbihwZXJtdXRhdGlvbiksIGVuZChwZXJtdXRhdGlvbiksIHJuZyk7CiAgICAgICAgVlUgc2Vjb25kX2NvcHkocGVybXV0YXRpb24pOwogICAgICAgIGNvbnN0IGF1dG8gY250ID0gaW52ZXJ0KHBlcm11dGF0aW9uKTsKICAgICAgICBjb3V0IDw8IGV4cCA8PCAnICcgPDwgKGRvdWJsZSljbnQgLyBuIDw8ICdcbic7CgogICAgICAgIGludmVydChwZXJtdXRhdGlvbik7CiAgICAgICAgaWYgKHBlcm11dGF0aW9uICE9IHNlY29uZF9jb3B5KQogICAgICAgIHsKICAgICAgICAgICAgY291dCA8PCAiV3JvbmcgcmVzdWx0XG4iOwogICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICB9CiAgICB9Cn0K