首页 > 其他分享 >gym 102994M Travel Dream 题解

gym 102994M Travel Dream 题解

时间:2023-07-09 18:22:05浏览次数:37  
标签:tmp Set mid2 题解 gym mx2 mx3 && Dream

给定带权无向图,求最大 \(k\) 元环。

\(n,m\leq 300,3\leq k\leq 10\),无重边。

把 \(k=3\) 判掉,可以 \(O(m^2)\) 轻松解决。

把 \(k\) 元环拆成长度为 \(\dfrac{k}{2}-1\) 的链 \(+\) 长度 \(k-\dfrac{k}{2}-1\) 的链 \(+\) 连接两条链的两条边。(长度指边的个数)

问题:两条链需要无交。

解决方案:随机对每个点二元染色,钦定一条链为白色,另一条为黑色。

接下来只需要对每对点,找到以他们为链头权最大的长度 \(1\leq k'\leq 4\) 的链。

\(k'=1\):链退化为,\(O(m)\)。

\(k'=2\):枚举两条边判断是否有交,\(O(m^2)\)。

\(k'=3\):枚举两条无交的边,判断能否在其之间再连一条边,\(O(m^2)\)。

\(k'=4\):先进行 \(k'=2\) 的枚举,枚举时保留权值前三大的链,构造长度为 \(4\) 的链 \(=\) 边 \(+\) 长度为 \(2\) 的链 \(+\) 边,其中长为 \(2\) 的链的中点不能与其他四个点有交,所以保留前三大。\(O(m^2)\)。

预处理后即可 \(O(m^2)\) 简单合并黑白链。

复杂度支持做 \(O(m)\) 次随机化,误差可以接受。

卡随机化精度,请善用随机化技巧。

#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>

// #define inf 0x3f3f3f3f3f3f3f3f
#define N 310
unsigned int sd = 114514;
bool rnd()
{
	sd ^= sd << 13;
	sd ^= sd >> 7;
	sd ^= sd << 11;
	return sd % 2;
}
int n, m, K;
int x_[N << 1], y_[N << 1], z_[N << 1];
int mp[2][N][N];
int ans;
bool col[N];
int f[2][N][N];

inline void ckmax(int &x, int y) { x = x > y ? x : y; }

inline void Set(bool c, int x, int y, int z)
{
	ckmax(f[c][x][y], z);
	ckmax(f[c][y][x], z);
}

bool check(bool c, int i)
{
	return col[x_[i]] == c && col[y_[i]] == c;
}

int common(int i, int j)
{
	if (x_[i] == x_[j] || x_[i] == y_[j])
		return x_[i];
	if (y_[i] == x_[j] || y_[i] == y_[j])
		return y_[i];
	return 0;
}

inline void solve1(bool c)
{
	for (int i = 1; i <= m; i++)
		if (check(c, i))
			Set(c, x_[i], y_[i], z_[i]);
}

inline void solve2(bool c)
{
	for (int i = 1; i <= m; i++)
		if (check(c, i))
			for (int j = i + 1, t; j <= m; j++)
				if (check(c, j) && (t = common(i, j)))
					Set(c, x_[i] ^ y_[i] ^ t, x_[j] ^ y_[j] ^ t, z_[i] + z_[j]);
}

inline void Link3(bool c, int i, int j)
{
	if (mp[c][x_[i]][x_[j]])
		Set(c, y_[i], y_[j], z_[i] + z_[j] + mp[c][x_[i]][x_[j]]);
	if (mp[c][x_[i]][y_[j]])
		Set(c, y_[i], x_[j], z_[i] + z_[j] + mp[c][x_[i]][y_[j]]);
	if (mp[c][y_[i]][x_[j]])
		Set(c, x_[i], y_[j], z_[i] + z_[j] + mp[c][y_[i]][x_[j]]);
	if (mp[c][y_[i]][y_[j]])
		Set(c, x_[i], x_[j], z_[i] + z_[j] + mp[c][y_[i]][y_[j]]);
}

inline void solve3(bool c)
{
	for (int i = 1; i <= m; i++)
		if (check(c, i))
			for (int j = i + 1; j <= m; j++)
				if (check(c, j) && !common(i, j))
					Link3(c, i, j);
}

struct node
{
	int mx1, mid1, mx2, mid2, mx3, mid3;
	node()
	{
		mx1 = mx2 = mx3 = 0;
		mid1 = mid2 = mid3 = 0;
	}
	bool empty() { return !mx1; }
	void merge(int mx, int mid)
	{
		if (mx >= mx1)
		{
			mx3 = mx2, mx2 = mx1, mx1 = mx;
			mid3 = mid2, mid2 = mid1, mid1 = mid;
		}
		else if (mx >= mx2)
		{
			mx3 = mx2, mx2 = mx;
			mid3 = mid2, mid2 = mid;
		}
		else if (mx >= mx3)
		{
			mx3 = mx;
			mid3 = mid;
		}
	}
} g[2][N][N];

node tmp;

inline void Link4(bool c, int i, int j)
{
	if (!g[c][x_[i]][x_[j]].empty())
	{
		tmp = g[c][x_[i]][x_[j]];
		if (tmp.mx1 && tmp.mid1 != y_[i] && tmp.mid1 != y_[j])
			Set(c, y_[i], y_[j], z_[i] + tmp.mx1 + z_[j]);
		if (tmp.mx2 && tmp.mid2 != y_[i] && tmp.mid2 != y_[j])
			Set(c, y_[i], y_[j], z_[i] + tmp.mx2 + z_[j]);
		if (tmp.mx3 && tmp.mid3 != y_[i] && tmp.mid3 != y_[j])
			Set(c, y_[i], y_[j], z_[i] + tmp.mx3 + z_[j]);
	}
	if (!g[c][x_[i]][y_[j]].empty())
	{
		tmp = g[c][x_[i]][y_[j]];
		if (tmp.mx1 && tmp.mid1 != y_[i] && tmp.mid1 != x_[j])
			Set(c, y_[i], x_[j], z_[i] + tmp.mx1 + z_[j]);
		if (tmp.mx2 && tmp.mid2 != y_[i] && tmp.mid2 != x_[j])
			Set(c, y_[i], x_[j], z_[i] + tmp.mx2 + z_[j]);
		if (tmp.mx3 && tmp.mid3 != y_[i] && tmp.mid3 != x_[j])
			Set(c, y_[i], x_[j], z_[i] + tmp.mx3 + z_[j]);
	}
	if (!g[c][y_[i]][x_[j]].empty())
	{
		tmp = g[c][y_[i]][x_[j]];
		if (tmp.mx1 && tmp.mid1 != x_[i] && tmp.mid1 != y_[j])
			Set(c, x_[i], y_[j], z_[i] + tmp.mx1 + z_[j]);
		if (tmp.mx2 && tmp.mid2 != x_[i] && tmp.mid2 != y_[j])
			Set(c, x_[i], y_[j], z_[i] + tmp.mx2 + z_[j]);
		if (tmp.mx3 && tmp.mid3 != x_[i] && tmp.mid3 != y_[j])
			Set(c, x_[i], y_[j], z_[i] + tmp.mx3 + z_[j]);
	}
	if (!g[c][y_[i]][y_[j]].empty())
	{
		tmp = g[c][y_[i]][y_[j]];
		if (tmp.mx1 && tmp.mid1 != x_[i] && tmp.mid1 != x_[j])
			Set(c, x_[i], x_[j], z_[i] + tmp.mx1 + z_[j]);
		if (tmp.mx2 && tmp.mid2 != x_[i] && tmp.mid2 != x_[j])
			Set(c, x_[i], x_[j], z_[i] + tmp.mx2 + z_[j]);
		if (tmp.mx3 && tmp.mid3 != x_[i] && tmp.mid3 != x_[j])
			Set(c, x_[i], x_[j], z_[i] + tmp.mx3 + z_[j]);
	}
}

inline void solve4(bool c)
{
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			g[c][i][j] = g[0][0][0];
	for (int i = 1; i <= m; i++)
		if (check(c, i))
			for (int j = i + 1, t; j <= m; j++)
				if (check(c, j) && (t = common(i, j)))
				{
					g[c][x_[i] ^ y_[i] ^ t][x_[j] ^ y_[j] ^ t].merge(z_[i] + z_[j], t);
					g[c][x_[j] ^ y_[j] ^ t][x_[i] ^ y_[i] ^ t].merge(z_[i] + z_[j], t);
				}
	for (int i = 1; i <= m; i++)
		if (check(c, i))
			for (int j = i + 1, t; j <= m; j++)
				if (check(c, j) && !common(i, j))
					Link4(c, i, j);
}

inline void sve(bool c, int p)
{
	if (p == 1)
		solve1(c);
	else if (p == 2)
		solve2(c);
	else if (p == 3)
		solve3(c);
	else if (p == 4)
		solve4(c);
}

inline void Link0(int i, int j)
{
	if (f[0][x_[i]][x_[j]] && f[1][y_[i]][y_[j]])
		ckmax(ans, f[0][x_[i]][x_[j]] + f[1][y_[i]][y_[j]] + z_[i] + z_[j]);
}

inline void solve(int op)
{
	for (int i = 1; i <= n; i++)
		col[i] = rnd();
	memset(f, 0, sizeof(f));
	memset(mp, 0, sizeof(mp));
	if (K == 3)
	{
		for (int i = 1; i <= m; i++)
			mp[0][x_[i]][y_[i]] = mp[0][y_[i]][x_[i]] = z_[i];
		for (int i = 1; i <= m; i++)
			for (int j = i + 1, t; j <= m; j++)
				if ((t = common(i, j)))
					if (mp[0][x_[i] ^ y_[i] ^ t][x_[j] ^ y_[j] ^ t])
						ckmax(ans, z_[i] + z_[j] + mp[0][x_[i] ^ y_[i] ^ t][x_[j] ^ y_[j] ^ t]);
		return;
	}
	for (int i = 1; i <= m; i++)
		if (col[x_[i]] == col[y_[i]])
			mp[col[i]][x_[i]][y_[i]] = mp[col[i]][y_[i]][x_[i]] = z_[i];
	int R = K / 2 - 1;
	int L = K - K / 2 - 1;
	if (op)//fuck
		std::swap(L, R);
	sve(0, L);
	sve(1, R);
	for (int i = 1; i <= m + m; i++)
		if (col[x_[i]] == 0 && col[y_[i]] == 1)
			for (int j = 1; j <= m + m; j++)
				if (col[x_[j]] == 0 && col[y_[j]] == 1)
					Link0(i, j);
}

int read()
{
	int x = 0;
	char c = getchar();
	while (c < '0' || '9' < c)
		c = getchar();
	while ('0' <= c && c <= '9')
	{
		x = (x << 3) + (x << 1) + (c ^ 48);
		c = getchar();
	}
	return x;
}

signed main()
{
	n = read(), m = read(), K = read();
	for (int i = 1; i <= m; i++)
		x_[i] = read(), y_[i] = read(), z_[i] = read();
	for (int i = 1; i <= m; i++)
		x_[i + m] = y_[i], y_[i + m] = x_[i], z_[i + m] = z_[i];
	int op = 0;
	while (1.0 * clock() / CLOCKS_PER_SEC <= 2.97)
		solve(op ^= 1);
	if (!ans)
		printf("impossible\n");
	else
		printf("%d\n", ans);
	return 0;
}

标签:tmp,Set,mid2,题解,gym,mx2,mx3,&&,Dream
From: https://www.cnblogs.com/ningago/p/17539116.html

相关文章

  • 「NOIP 模拟赛 20230709」T3 - 与行星相会 题解
    题目大意原题有一个\(n\timesn\)的点阵,将相邻的点连边得到一个\((n-1)\times(n-1)\)的网格。\(q\)次操作,每次删掉一条边,求删掉后边两端的点是否仍在一个连通块内。强制在线。题解显然,由于对偶图的性质,原图的一个割对应对偶图中的一个环,所以只需要删掉一条边时在对偶图中......
  • 寻找页码题解
    首先看题目,我也不知道这一题的出处。。。。在网上找了很久也没找到。。。题目描述从第1页开始,页码组成的数字序列如下:123..101112..99100101...这串序列又被称之为连写数。给定一个0到9之中的单独一位数字a,请问在这串序列中,第k次出现a,是在哪一页上?以数码1为例,第......
  • 华泰证券FINTECH决赛第二题题解
    被第二题搞得坐牢2个半小时,在最后10分钟才确定推出的求和公式没问题,是除法取模不规范导致求解有偏差,只能说菜是原罪。这里贴一下赛后修改的代码,希望能对列位有些帮助,欢迎巨佬指导。思路:分奇偶讨论固定长度下伪回文串的数量,定义长度为\(n\)的伪回文串的数量为\(a_{n}\):(1)\(n\)......
  • P7112 题解
    题意简述模板题,求一个\(n\timesn(n\le600)\)的方阵的行列式模一个正整数\(p(1\lep\le10^9+7)\)的值(\(p\)不一定是质数)。题目分析这个题的最终代码其实很简单,重点在于过程。说实话,我在做这个题之前也就只知道个行列式的定义,只会暴力硬算。做了这个题才了解了行列式有那......
  • 关于Azure-平台-Redhat-Linux-服务器时间同步的问题解决
    首先说明一下,关于Azure平台中国区,是没有RedhatLinux系统镜像的于是笔者这边是通过在Windows系统 Hyper-V管理器中安装完Redhat8.x操作系统后,最后将系统磁盘转换成转换为VHD格式然后经过一系列操作、最终在Azure平台上形成了自己的并且加固过的RedHatEnterpriseLinuxre......
  • 【题解】 [APIO2007] 动物园
    目录题目链接原题描述题目描述输入格式输出格式样例#1样例输入#1样例输出#1样例#2样例输入#2样例输出#2提示题意概括思路历程1.与环相关2.设计状态代码实现题目链接原题描述[APIO2007]动物园题目描述新建的圆形动物园是亚太地区的骄傲。圆形动物园坐落于太平洋的一个......
  • 洛谷题解——【模板】堆
    题目链接:【模板】堆【模板】堆题目描述给定一个数列,初始为空,请支持下面三种操作:给定一个整数\(x\),请将\(x\)加入到数列中。输出数列中最小的数。删除数列中最小的数(如果有多个数最小,只删除\(1\)个)。输入格式第一行是一个整数,表示操作的次数\(n\)。接下来\(n\)......
  • 并发网络周测题解释版
    并发网络周测题【一】理论篇1.简述OSI七层协议OSI七层协议(OpenSystemsInterconnection)是一种用于计算机网络通信的参考模型。该模型将网络通信过程分解为七个不同的层次,每个层次负责特定的功能和任务,这有助于网络设备和应用程序之间的协作和互操作性。【1】物理层(Physica......
  • CF500C New Year Book Reading 题解
    这一题是一道比较复杂的贪心(对于本蒟蒻来说)假如两本书\(a\)和\(b\),先看\(a\)再看\(b\),那么我们开始的时候就把\(a\)放在上面。这样的话,我们看\(a\)时就不需要搬动\(b\),看\(b\)的时候会搬动\(a\)。而一开始如果把放在上面,看\(a\)的时候需要搬动\(b\),看\(b\)......
  • AtCoder Beginner Contest 308 题解
    https://atcoder.jp/contests/abc308/tasks_printA-NewScheme过水已隐藏。#include<bits/stdc++.h>#include<ext/pb_ds/assoc_container.hpp>#include<ext/pb_ds/tree_policy.hpp>#include<ext/pb_ds/hash_policy.hpp>usingnamespacestd;u......