题意
传送门 Codeforces 1654F Minimal String Xoration
题解
考虑对以
j
=
[
0
,
2
n
)
j = [0,2^n)
j=[0,2n) 的字符串进行排序。排序思路与倍增求后缀数组类似。倍增正确性证明如下:
[
k
⊕
i
,
(
k
+
1
)
⊕
i
,
⋯
)
=
[
0
⊕
(
k
⊕
i
)
,
1
⊕
(
k
⊕
i
)
,
⋯
)
,
k
=
2
n
,
序
列
长
度
小
于
k
[k\oplus i, (k + 1)\oplus i,\cdots) = [0\oplus(k\oplus i), 1\oplus(k\oplus i),\cdots), k = 2^n, 序列长度小于k
[k⊕i,(k+1)⊕i,⋯)=[0⊕(k⊕i),1⊕(k⊕i),⋯),k=2n,序列长度小于k 总时间复杂度
O
(
n
log
2
n
)
O(n\log^2n)
O(nlog2n)。
#include <bits/stdc++.h>
using namespace std;
int N;
string S;
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N >> S;
vector<int> a(1 << N), rnk(1 << N), tmp(1 << N);
for (int i = 0; i < 1 << N; ++i)
a[i] = i, rnk[i] = S[i];
for (int k = 1; k <= 1 << N; k *= 2)
{
auto cmp = [&](const int &i, const int &j)
{
if (rnk[i] != rnk[j])
return rnk[i] < rnk[j];
int ri = k == (1 << N) ? -1 : rnk[k ^ i];
int rj = k == (1 << N) ? -1 : rnk[k ^ j];
return ri < rj;
};
sort(a.begin(), a.end(), cmp);
tmp[a[0]] = 0;
for (int i = 1; i < 1 << N; ++i)
tmp[a[i]] = tmp[a[i - 1]] + (cmp(a[i - 1], a[i]) ? 1 : 0);
copy(tmp.begin(), tmp.end(), rnk.begin());
}
for (int i = 0; i < 1 << N; ++i)
cout << S[i ^ a[0]];
cout << '\n';
return 0;
}