ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1685D Permutation Weight [贪心,构造]

2022-07-20 00:01:26  阅读:180  来源: 互联网

标签:ch Weight int MN CF1685D Permutation inline Mod define


传送门

思路

令 \(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有