专栏文章

题解:CF1666K Kingdom Partition

CF1666K题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minn0iq2
此快照首次捕获于
2025/12/02 05:04
3 个月前
此快照最后确认于
2025/12/02 05:04
3 个月前
查看原文
考虑一条边两个端点 uuvv 所在集合的贡献系数:
AABBCC
AA220011
BB002211
CC111122
我们发现这和“两集选一”问题看起来相似,考虑最小割,但是这是“三集选一”,源点和汇点仅能刻画两种状态,于是我们将一个点 uu 拆成两个点 u1,u2u_1, u_2,并声称若 u1u_1 在源点一侧且 u2u_2 在汇点一侧则 uuAA 中,若 u1u_1 在汇点一侧且 u2u_2 在源点一侧则 uuBB 中,否则 uuCC 中。我们将原图中的边 (u,v)(u, v) 变为 (u1,v2),(u2,v1)(u_1, v_2), (u_2, v_1),再考量 u1,u2u_1, u_2v1,v2v_1, v_2 所在集合的贡献系数:
SSSSSTSTTSTSTTTT
SSSS00111122
STST11220011
TSTS11002211
TTTT22111100
我们惊奇的发现:
STSTTSTSTTTT
STST220011
TSTS002211
TTTT111100
以及
TSTSSTSTSSSS
TSTS220011
STST002211
SSSS111100
与最开头给出的系数完全相同。同时我们又发现选 SSSS 和选 TTTT 本质相同,换而言之我们可以将所有 TTTT 换成 SSSS,所以 SSSSTTTT 间的 22 系数在最小割中会被忽略。
综上所述,我们对 u1,u2u_1, u_2 分别做“两集选一”即可,时间复杂度是最大流的 O(n2m)\mathcal{O}(n^2m)
Code:
CPP
#include<bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))

using namespace std;

const int maxn = 1000 + 10, maxm = 2000 + 10, maxv = maxn << 1;

struct{
    int v, nex;
    long long w;
} edge[maxm << 3];

int n, m, s, t, a, b;
long long flow = 0;
int dep[maxv];
bitset<maxv> res;
int head[maxv], hd[maxv], top = 1;

inline void add(int u, int v, long long w, bool o = true){
    edge[++top].v = v, edge[top].w = w, edge[top].nex = head[u], head[u] = top, o && (add(v, u, 0, false), 1538);
}

inline bool bfs(){
    queue<int> q;
    q.push(s), mem(dep, 0), dep[s] = 1;
    while (!q.empty()){
        const int u = q.front();
        q.pop();
        for (int i = head[u]; i; i = edge[i].nex){
            const int v = edge[i].v;
            const long long w = edge[i].w;
            w && !dep[v] && (q.push(v), dep[v] = dep[u] + 1);
        }
    }
    return dep[t];
}

inline long long dfs(int u, long long fl){
    if (u == t){
        return fl;
    }
    long long sum = 0;
    for (int &i = hd[u]; i; i = edge[i].nex){
        const int v = edge[i].v;
        const long long w = edge[i].w;
        if (dep[v] == dep[u] + 1 && w){
            const long long f = dfs(v, min(w, fl));
            edge[i].w -= f, edge[i ^ 1].w += f, sum += f, fl -= f;
            if (!fl){
                break;
            }
        }
    }
    return sum;
}

inline void dfs2(int u){
    res.set(u);
    for (int i = head[u]; i; i = edge[i].nex){
        const int v = edge[i].v;
        const long long w = edge[i].w;
        w && !res.test(v) && (dfs2(v), 1538);
    }
}

int main(){
    scanf("%d %d %d %d", &n, &m, &a, &b), s = n << 1 | 1, t = s + 1, add(s, a, 1e18), add(a + n, t, 1e18), add(s, b + n, 1e18), add(b, t, 1e18);
    while (m--){
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w), add(u, v + n, w), add(u + n, v, w), add(v + n, u, w), add(v, u + n, w);
    }
    while (bfs()){
        memcpy(hd, head, sizeof(head)), flow += dfs(s, 1e18);
    }
    printf("%lld\n", flow), dfs2(s);
    for (int i = 1; i <= n; i++){
        putchar(res.test(i) && !res.test(i + n) ? 'A' : !res.test(i) && res.test(i + n) ? 'B' : 'C');
    }

return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...