题解 [ABC371G] Lexicographically Smallest Permutation(中文/English)
本题解提供英文版,位于示例代码之后。
English version of this editorial is provided after the sample code.
官方题解竟然用 Python 来算高精度 lcm,我来提供一个可以避免一切大整数运算的方法。
考察
假设贪心地填完了前
直接做的复杂度为
示例代码 / Sample code:
// Problem: G - Lexicographically Smallest Permutation
// Contest: AtCoder - AtCoder Beginner Contest 371
// URL: https://atcoder.jp/contests/abc371/tasks/abc371_g
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x, y, z) for(int x = (y); x <= (z); ++x)
#define per(x, y, z) for(int x = (y); x >= (z); --x)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do {freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);} while(false)
#define endl '\n'
using namespace std;
typedef long long ll;
mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
int randint(int L, int R) {
uniform_int_distribution<int> dist(L, R);
return dist(rnd);
}
template<typename T> void chkmin(T& x, T y) {if(y < x) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
template<int mod>
inline unsigned int down(unsigned int x) {
return x >= mod ? x - mod : x;
}
template<int mod>
struct Modint {
unsigned int x;
Modint() = default;
Modint(unsigned int x) : x(x) {}
friend istream& operator>>(istream& in, Modint& a) {return in >> a.x;}
friend ostream& operator<<(ostream& out, Modint a) {return out << a.x;}
friend Modint operator+(Modint a, Modint b) {return down<mod>(a.x + b.x);}
friend Modint operator-(Modint a, Modint b) {return down<mod>(a.x - b.x + mod);}
friend Modint operator*(Modint a, Modint b) {return 1ULL * a.x * b.x % mod;}
friend Modint operator/(Modint a, Modint b) {return a * ~b;}
friend Modint operator^(Modint a, int b) {Modint ans = 1; for(; b; b >>= 1, a *= a) if(b & 1) ans *= a; return ans;}
friend Modint operator~(Modint a) {return a ^ (mod - 2);}
friend Modint operator-(Modint a) {return down<mod>(mod - a.x);}
friend Modint& operator+=(Modint& a, Modint b) {return a = a + b;}
friend Modint& operator-=(Modint& a, Modint b) {return a = a - b;}
friend Modint& operator*=(Modint& a, Modint b) {return a = a * b;}
friend Modint& operator/=(Modint& a, Modint b) {return a = a / b;}
friend Modint& operator^=(Modint& a, int b) {return a = a ^ b;}
friend Modint& operator++(Modint& a) {return a += 1;}
friend Modint operator++(Modint& a, int) {Modint x = a; a += 1; return x;}
friend Modint& operator--(Modint& a) {return a -= 1;}
friend Modint operator--(Modint& a, int) {Modint x = a; a -= 1; return x;}
friend bool operator==(Modint a, Modint b) {return a.x == b.x;}
friend bool operator!=(Modint a, Modint b) {return !(a == b);}
};
const int N = 2e5 + 5;
int n, p[N], a[N], vis[N], req[N], ans[N];
vector<int> divs[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n;
rep(i, 1, n) cin >> p[i];
rep(i, 1, n) cin >> a[i];
rep(i, 2, n) {
if(divs[i].empty()) {
for(ll d = i; d <= n; d *= i) {
for(int j = d; j <= n; j += d) {
divs[j].push_back(d);
}
}
}
}
rep(i, 1, n) req[i] = -1;
rep(i, 1, n) {
if(!vis[i]) {
vector<int> cyc;
for(int u = i; !vis[u]; u = p[u]) {
cyc.push_back(u);
vis[u] = 1;
}
// for(int u : cyc) cout << u << " "; cout << endl;
int len = cyc.size(), steps = -1;
rep(s, 0, len - 1) {
bool ok = true;
for(int d : divs[len]) {
if(req[d] != -1 && s % d != req[d]) {
ok = false;
break;
}
}
if(ok) {
if(steps == -1 || a[cyc[s]] < a[cyc[steps]]) {
steps = s;
}
}
}
rep(i, 0, len - 1) ans[cyc[i]] = a[cyc[(i + steps) % len]];
for(int d : divs[len]) req[d] = steps % d;
}
}
rep(i, 1, n) cout << ans[i] << " \n"[i == n];
return 0;
}
The official solution surprisingly uses Python to compute LCM of big integers. Let me present an algorithm that avoids all big integer computations.
Consider each cycle in the permutation graph
Suppose the first
The direct approach has a time complexity of