This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <iostream>
#include <vector>
#include <cassert>
using ll = long long;
using namespace std;
ll get_inversion(vector<int>& p) {
int n = p.size();
ll ans = 0;
for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) {
ans += p[i] > p[j];
}
return ans;
}
vector<int> combine_permutations(vector<int> a, vector<int> b) {
int n = a.size();
vector<int> ans(n);
for (int i = 0; i < n; ++i) {
ans[i] = b[a[i]];
}
return ans;
}
vector<int> reverse_permutation(vector<int> a) {
int n = a.size();
vector<int> ans(n);
for (int i = 0; i < n; ++i)
ans[a[i]] = i;
return ans;
}
ll get_inv_block(vector<int>::iterator begin, vector<int>::iterator end) {
int n = end - begin;
auto mid = begin + n / 2;
vector<int> cless(n, 0);
for (auto it = mid; it < end; ++it) {
++cless[*it];
}
for (int i = 1; i < n; ++i)
cless[i] += cless[i - 1];
ll ans = 0;
for (auto it = begin; it < mid; ++it) {
ans += cless[*it];
}
return ans;
}
void split_into_halves(vector<int>::iterator begin, vector<int>::iterator end) {
int n = end - begin;
auto mid = begin + n / 2;
vector<int> pos0(n, 0);
vector<int> pos1(n, 0);
for (auto it = begin; it < end; ++it) {
if (it < mid)
++pos0[*it];
else
++pos1[*it];
}
--pos0[0];
--pos1[0];
for (int i = 1; i < n; ++i) {
pos0[i] += pos0[i - 1];
pos1[i] += pos1[i - 1];
}
for (auto it = begin; it < end; ++it) {
if (it < mid)
it[0] = pos0[*it];
else
it[0] = pos1[*it];
}
}
pair<ll, string> get_ans(vector<int> p) {
int n = p.size();
ll ans = 0;
int ansx = 0;
for (int bt = n / 2; bt > 0; bt /= 2) {
ll inv0 = 0;
for (auto it = p.begin(); it < p.end(); it += bt * 2) {
inv0 += get_inv_block(it, it + bt * 2);
split_into_halves(it, it + bt * 2);
}
ll inv1 = 1ll * (n / 2) * bt - inv0;
if (inv1 < inv0) {
ans += inv1;
vector<int> op(n);
for (int i = 0; i < n; ++i)
op[i] = i ^ bt;
p = combine_permutations(op, p);
ansx += bt;
} else {
ans += inv0;
}
}
string ansa = "";
for (int bt = 1; bt < n; bt *= 2) {
ansa.push_back('2');
if (ansx & bt)
ansa.push_back('1');
}
return {ans, ansa};
}
signed main() {
int N;
cin >> N;
int m = (1 << N);
vector<int> p(m);
for (int i = 0; i < m; ++i)
cin >> p[i];
if (N == 0) {
cout << "0\n";
cout << "1\n";
return 0;
}
vector<int> op1(m);
vector<int> op2(m);
for (int i = 0; i < m; ++i) {
op1[i] = i ^ (m / 2);
op2[i] = (i >> 1) + ((i & 1) << (N - 1));
}
op2 = reverse_permutation(op2);
//for (int i = 0; i < m; ++i)
//cout << op2[i] << ' ';
//cout << endl;
ll ans = 1ll * m * m;;
string ansa;
string curst = "";
for (int t = 0; t < N; ++t) {
auto [nans, nansa] = get_ans(p);
if (nans < ans) {
ans = nans;
ansa = curst + nansa;
}
p = combine_permutations(op2, p);
curst.push_back('2');
}
cout << ans << '\n';
cout << ansa << '\n';
//for (int i = 0; i < m; ++i)
//cout << p[i] << ' ';
//cout << endl;
//for (auto x : ansa) {
//if (x == '1')
//p = combine_permutations(op1, p);
//else
//p = combine_permutations(op2, p);
//}
//for (int i = 0; i < m; ++i)
//cout << p[i] << ' ';
//cout << endl;
//cout << get_inversion(p) << endl;
//assert(get_inversion(p) == ans);
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |