CF1685D Permutation Weight [贪心,构造]
作者:互联网
思路
令 \(p' = p^{-1}\),即 \(p'_{p_i} = i\),则原题等价于最小化 \(\sum |p'_{q_i} - q_{i+1}|\)。显然,当所有 \(i\) 都满足 \(p'_{q_i} = q_{i+1}\) 时原式取最小值,但这时 \(q\) 不一定是一个排列。容易发现,排列 \(q\) 给出了一个在 \(p'\) 形成的图上遍历的顺序,考虑 \(p'\) 的置换分解,对每个环染色,那么为了让更多 \(i\) 满足 \(p'_{q_i} = q_{i+1}\),\(q\) 应当尽可能在同色的环上跳转。设有 \(k\) 个这样的环。
考虑连边 \(p'_{q_i} \to q_{i+1}\),则每个点的入度和出度恰为 \(1\),因此它们形成一些环。注意到大小为 \(m\) 的环对答案的贡献至少为 \(2(m-1)\),取到这个下界当且仅当环上的点编号连续且是单峰的。又因为 \(q\) 需要能够遍历整张图,这还要求将每个置换环缩点后所有颜色必须连通。大小为 \(m\) 的环至多能减少 \(m-1\) 个颜色连通块,而总共需要减少 \(k-1\) 个颜色连通块,则 \(\sum (m-1) \geq k-1\),故答案有下界 \(2(k-1)\)。
事实上这个下界可以达到,当且仅当这张图合法,且每个环对答案的贡献都到达了下界,并且这些环不会多次合并某两个颜色。容易发现,合法的环会覆盖 \(1 \sim n\) 的一个完整的区间。
对于 Easy Version,只需枚举 \(i\),若 \(i\) 和 \(i+1\) 颜色不同且它们未被合并就将他们合并,最后把区间还原成环即可。
对于 Hard Version,按照字典序添加每一条边,我们的目标是判断目前加入的边能否构造出到达下界的解。显然,已经连出的边只可能形成环,单增的链或单减的链。容易得到合法的条件:
-
不存在某两条单增链或单减链相交,即每条链的开头都不会被其他链覆盖。
-
不存在未连边的点同时被单增链及单减链覆盖。
-
没有某两种颜色被重复连边。只需检查所有颜色不同的 \(i\) 和 \(i + 1\),若 \((i,i+1)\) 被某条边覆盖就将他们对应的颜色连边,判断是否成环即可。
-
所有颜色连通。只需检查所有 \(i\) 和 \(i+1\),若 \(i\) 不为某个区间的右端点且 \(i+1\) 不为某个区间的左端点就将他们对应的颜色连边,判断是否连通即可。
时间复杂度 \(O(n^3)\)。
Code
/*
也许所有的执念 就像四季的更迭
没有因缘 不需致歉
是否拥抱着告别 就更能读懂人间
还是感慨 更多一点
*/
#include <bits/stdc++.h>
#define pii pair<int, int>
#define mp(x, y) make_pair(x, y)
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define int long long
#define mem(x, v, n) memset(x, v, sizeof(int) * (n))
#define mcpy(x, y, n) memcpy(x, y, sizeof(int) * (n))
#define lob lower_bound
#define upb upper_bound
using namespace std;
inline int read() {
int x = 0, w = 1;char ch = getchar();
while (ch > '9' || ch < '0') { if (ch == '-')w = -1;ch = getchar(); }
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return x * w;
}
inline int min(int x, int y) { return x < y ? x : y; }
inline int max(int x, int y) { return x > y ? x : y; }
const int MN = 5e2 + 5;
const int Mod = 1e9 + 7;
inline void Pls(int &x, int y) { x += y; if (x >= Mod) x -= Mod; }
inline void Dec(int &x, int y) { x -= y; if (x < 0) x += Mod; }
inline int qPow(int a, int b = Mod - 2, int ret = 1) {
while (b) {
if (b & 1) ret = ret * a % Mod;
a = a * a % Mod, b >>= 1;
}
return ret;
}
// #define dbg
int N, p[MN], mp[MN], col[MN], cnt, in[MN], out[MN], ans[MN], L[MN], R[MN], vis[MN];
vector <int> G[MN];
inline void DFS(int u) {
if (vis[u]) return;
vis[u] = 1;
for (int v : G[u]) DFS(v);
}
inline int Chk() {
for (int i = 1; i <= N; i++) if (L[i] + (in[i] == i) > 1 || R[i] + (in[i] == i) > 1) return 0;
for (int i = 1; i <= N; i++) if (!in[i] && !out[i] && L[i] && R[i]) return 0;
for (int i = 1; i <= cnt; i++) G[i].clear(), vis[i] = 0;
int c = 0, bc = 0;
for (int i = 1; i < N; i++) if (L[i + 1] || R[i]) c++, G[col[i]].pb(col[i + 1]), G[col[i + 1]].pb(col[i]);
for (int i = 1; i <= cnt; i++) if (!vis[i]) bc++, DFS(i);
if (c + bc > cnt) return 0;
for (int i = 1; i <= cnt; i++) G[i].clear(), vis[i] = 0;
c = 0;
for (int i = 1; i < N; i++) if (!(in[i] && out[i] && (in[i] <= i && out[i] <= i)) && !(in[i + 1] && out[i + 1] && (in[i + 1] >= i + 1 && out[i + 1] >= i + 1))) {
G[col[i]].pb(col[i + 1]);
G[col[i + 1]].pb(col[i]);
}
for (int i = 1; i <= cnt; i++) if (!vis[i]) c++, DFS(i);
return c > 1 ? 0 : 1;
}
inline void Add(int u, int v) {
out[u] = v, in[v] = u;
if (v < u) for (int i = u; i > v; i--) L[i]++;
else for (int i = u; i < v; i++) R[i]++;
}
inline void Del(int u, int v) {
out[u] = in[v] = 0;
if (v < u) for (int i = u; i > v; i--) L[i]--;
else for (int i = u; i < v; i++) R[i]--;
}
inline void Work() {
N = read();
for (int i = 1; i <= N; i++) p[i] = read(), mp[p[i]] = i;
cnt = 0;
for (int i = 1; i <= N; i++) col[i] = in[i] = out[i] = L[i] = R[i] = 0;
for (int i = 1; i <= N; i++) if (!col[i]) {
col[i] = ++cnt;
int x = mp[i];
while (x != i) col[x] = cnt, x = mp[x];
}
ans[1] = 1;
for (int i = 2; i <= N; i++) {
int u = ans[i - 1];
for (int j = 1; j <= N; j++) {
int v = p[j];
if (in[v]) continue;
Add(u, v);
if (Chk()) {
ans[i] = j; break;
}
Del(u, v);
}
}
for (int i = 1; i <= N; i++) printf("%lld%c", ans[i], " \n"[i == N]);
}
signed main(void) {
int T = read();
while (T--) Work();
return 0;
}
标签:ch,Weight,int,MN,CF1685D,Permutation,inline,Mod,define 来源: https://www.cnblogs.com/came11ia/p/16496291.html