ABC371G 题解
题意
给定两个排列
题解
我们由
这时我们发现,确定操作次数,最终的排列就确定;换句话说,确定某一个点移动多少步,整个排列就确定。由此,结合要让字典序最小,很自然地考虑到要让每个环上的第一个位置最小。
但是这样可能冲突。考虑有两个大小为
由于我们还要保证字典序最小,那么显然是尽量满足前面的环,即最小位置在最前面的环。后面的环怎么办?考虑枚举每个环上移动的步数
怎么判断某个
其中
那么可以分解出环长的质因子。设
于是我们做完了。
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 2e5 + 10;
int ps[N], minp[N], res[N], z[N], p[N], w[N], f[N], nr = 0;
bool vis[N];
void sieve (void)
{
for (int i = 2; i < N; i++) {
if (!minp[i]) ps[++nr] = i, minp[i] = i;
for (int j = 1; ps[j] * i < N; j++) {
minp[i * ps[j]] = ps[j];
if (i % ps[j] == 0) break;
}
}
}
int main (void)
{
int n;
cin.tie (0)->sync_with_stdio (false);
cin >> n;
sieve ();
memset (f, -1, sizeof f);
for (int i = 1; i <= n; i++) cin >> w[i];
for (int i = 1; i <= n; i++) cin >> z[i];
for (int i = 1; i <= n; i++) if (!vis[i]) {
int j = i;
vector<int> q, p;
while (!vis[j]) vis[j] = true, q.push_back (j), j = w[j];
int l = q.size (), t = l;
while (t > 1) {
int u = minp[t], w = 1;
while (t % u == 0) t /= u, p.push_back (w *= u);
}
int k = -1;
for (int i = 0; i < l; i++) {
for (auto j : p) if (f[j] != -1 && i % j != f[j]) goto nxt;
if (k == -1 || z[q[k]] > z[q[i]]) k = i;
nxt:;
}
for (int i = 0; i < l; i++) res[q[i]] = z[q[(i + k) % l]];
for (auto v : p) f[v] = k % v;
}
for (int i = 1; i <= n; i++) cout << res[i] << " \n"[i == n];
return 0;
}