首页 > 其他分享 >【大联盟】20230714 T1 三分网络(tri) 题解 CF1666K 【Kingdom Partition】

【大联盟】20230714 T1 三分网络(tri) 题解 CF1666K 【Kingdom Partition】

时间:2023-07-25 11:47:47浏览次数:52  
标签:tri dep 20230714 int 题解 ll read add ans

题目描述

here

题解

赛时得分:\(30/30\),想了很久网络流最后不会。

感觉这题就纯纯对脑洞,因为把题目中的 \(2\) 改成 \(3\) 就做不了)))不过还是相当有意思的。

考虑如下建模方式:

首先,考虑最小割。对于每个点 \(i\),我们用两个点 \(x_{i}\),\(y_i\) 来表示。

\(x_i\) 表示 \(i\) 号点是否在 A,\(y_i\) 表示 \(i\) 号点是否在 B,则在 C 为 \(1-x_i-y_i\)。

然后考虑按如下方式建图:对于边 \((u,v,w)\),我们连 \((x_u,y_v),(x_v,y_u),(y_u,x_v),(y_v,x_u)\),流量都为 \(w\)。


由于最小割相当于是最小化:

\[\sum_{(u,v,w)} wx_u(1-x_v) \]

并要求 \(x_S=1,x_T=0\)。


那现在考虑一下实际意义,发现恰好把同时在 \(A\) 的贡献 \(2w\),用两个点分别不在 \(B\) ,另一个在 \(A\) 算了两次,同时为 \(B\) 也是同理。

我们让只删 \(S\) 到 \(x_i\) 的边为 A,只删 \(y_i\) 到 \(T\) 的边为 B,其它情况为 C

注意到可能会出现 \(x_i=y_i=1\) 的不合法情况。但算下贡献就会发现,这种情况与 C 也就是 \(x_i=y_i=0\) 是等价的。

最后 \(a\) 号点必须在 A,\(b\) 号点必须在 B 的限制,我们直接 \((s,x_a,\infty),(s,y_b,\infty),(y_a,t,\infty),(x_b,t,\infty)\) 就可以了。

代码

#include <bits/stdc++.h>
#define SZ(x) (int) x.size() - 1
#define all(x) x.begin(), x.end()
#define ms(x, y) memset(x, y, sizeof x)
#define F(i, x, y) for (int i = (x); i <= (y); i++)
#define DF(i, x, y) for (int i = (x); i >= (y); i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T> void chkmax(T& x, T y) { x = max(x, y); }
template <typename T> void chkmin(T& x, T y) { x = min(x, y); }
template <typename T> void read(T &x) {
	x = 0; int f = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
const int N = 2010;
int n, m, A, B;
struct edge {
    int to;
    ll flow;
    unsigned pos;
};
vector <edge> a[N];
void add(int x, int y, ll flow) {
    // cout << x << " " << y << " " << flow << endl;
    a[x].push_back((edge) { y, flow, (unsigned) a[y].size() });
    a[y].push_back((edge) { x, 0, (unsigned) a[x].size() - 1 });
}
int dep[N];
unsigned cur[N];
queue <int> q;
bool bfs(int s, int t) {
    F(i, s, t) dep[i] = 0;
    dep[s] = 1;
    q.push(s);
    while (q.size()) {
        int x = q.front(); q.pop();
        for (edge i: a[x])
            if (i.flow && !dep[i.to]) {
                dep[i.to] = dep[x] + 1;
                q.push(i.to);
            }
    }
    return dep[t];
}
ll dfs(int x, int tt, ll lim) {
    if (x == tt) return lim;
    ll ans = 0, t;
    for (unsigned &i = cur[x]; i < a[x].size(); ++i)
        if (a[x][i].flow && dep[a[x][i].to] == dep[x] + 1 && (t = dfs(a[x][i].to, tt, min(lim, a[x][i].flow)))) {
            a[x][i].flow -= t, a[a[x][i].to][a[x][i].pos].flow += t;
            lim -= t, ans += t;
            if (!lim) return ans;
        }
    return ans;
}
ll dinic(int s, int t) {
    ll ans = 0;
    while (bfs(s, t)) {
        F(i, s, t) cur[i] = 0;
        ans += dfs(s, t, 1e18);
    } return ans;
}
signed main() {
    // freopen("tri.in", "r", stdin);
    // freopen("tri.out", "w", stdout);
    read(n), read(m), read(A), read(B);
    int s = 0, t = 2 * n + 1;
    add(s, A, 1e18);
    add(s, B + n, 1e18);
    add(A + n, t, 1e18);
    add(B, t, 1e18);
    F(i, 1, m) {
        int x, y, z; read(x), read(y), read(z);
        add(x, y + n, z);
        add(y, x + n, z);
        add(x + n, y, z);
        add(y + n, x, z);
    } cout << dinic(s, t) << endl;
	F(i, 1, n)
		if (dep[i] && !dep[i + n]) putchar('A');
		else if (!dep[i] && dep[i+n]) putchar('B');
			else putchar('C');
    return 0;
}

标签:tri,dep,20230714,int,题解,ll,read,add,ans
From: https://www.cnblogs.com/zhaohaikun/p/17579393.html

相关文章

  • 题解 [SDOI2009] HH的项链
    题目链接对于这类问区间不同数的总数,显然是不能用线段树直接维护的,毕竟不符合区间区间可加性。考虑对于一个右端点固定的询问,哪些数字实际上是有权值的。比如区间1332312,显然,实际上对于相同的数字,只有一个是有权值的,其他权值均为\(0\)。但是这样还是无法起到简化的作用......
  • 题解 链表 (chain)
    题目链接首先考虑没有修改怎么做。两种做法。想到询问的形式为保留\(\gek\)的连通块个数,那么先将全部数字按照权值排序,然后从后往前做一遍并查集,并同时统计连通块的数量,在询问时只需二分找到第一个\(\gek\)的位置,将这个位置的答案输出即可。注意考虑答案为\(0\)的情况......
  • 【大联盟】20230713 T1 方向矩阵(rect) 题解 CF1666A 【Admissible Map】
    题目描述here。题解赛时得分:60/100。想到了正解,但调不出来,就改写暴力了。。。首先,我们把问题转化成每个点都入度为\(1\)。我们考虑合法子串只有两种形式:注意到U和D,要么同时出现,要么同时不出现,因为如果存在U,就说明U所在这一行得到度数减少了,一定需要上一行D来弥补......
  • luogu P3203 [HNOI2010] 弹飞绵羊 题解
    题目传送门:P3203[HNOI2010]弹飞绵羊题意\(n\)个数,满足\(i<a_i≤N+1\),\(m\)次下面两种操作修改一个数\(a_i\)从\(x\)开始跳,\(x=a_x\),几次能够跳出序列\(n\leq2*10^5,m<10^5\)分析数据范围比较大,单纯搜索模拟肯定会T,那么考虑每次让他跳一段就......
  • Python - String Methodology
    >>>dir("")['__add__','__class__','__contains__','__delattr__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__&......
  • 题解 P7971【[KSN2021] Colouring Balls】
    postedon2022-10-0819:07:28|under题解|sourceproblem交互库有一个长为\(n\)的颜色序列,你可以询问区间\([l,r]\)中有多少种颜色,最后还原交互库手中的序列,只需要保持相对顺序不变。\(n\leq10^3\),最多询问次数\(Q=2000\)或\(Q=10^4\)。solution令\(C\)为\([1......
  • CF1051G Distinctification题解
    link首先可以发现,题目给定的两种操作为我们提供了“反悔机制”,所以有:结论\(1\):即任何一个可以到达的局面都能到达最优解。利用这个结论,首先我们先去重。继续提炼性质,与相差不到\(1\)的数为基准\(+1\)与\(-1\)操作,将这个数的变化范围限制在了一个区间,并且这个区间的数能......
  • 字符格式化-逐步总结-f-string
    Python3.6引入了一个新的格式化字符串的方法:f-string(formattedstring),它可以直接把变量写在字符串中,使得格式化的字符串看起来很直观。f可以小写,也可以用大写F。一、变量使用:例1:name='张三'print(f'姓名:{name}')>>>姓名:张三。简单说就是{}里直接加变量。例2:i=0print......
  • 题解 Codeforces Round 887 (Div 1+Div 2) / CF1853AB,CF1852ABCD
    下大分!悲!Div1只过了1A!!!但还是补完整场Div2吧。A.Desortinghttps://codeforces.com/problemset/problem/1853/Aproblem用操作:\([1,i]++,[i+1,n]--\),使得数组不单调不降,求最小操作次数。\(n\leq10^5\)。solution操作等同于在差分数组上选出\(i\),做\(c_1:=c_1+1,c_i:......
  • UOJ #284. 快乐游戏鸡题解(长链剖分+单调栈合并)
    UOJ#284.快乐游戏鸡题解(长链剖分+单调栈合并)题面一番战斗之后,程序猿被计算鸡们赶走了。随着垫子计算鸡一声令下:“追!”,于是计算鸡村全村上下开始乘胜追击。计算鸡们希望在新的一年到来之际给程序猿以重创,出掉这一年的恶气。可是程序猿一追就走,一走就跑,一跑就无影无踪。计算鸡......