首页 > 其他分享 >Luogu P9542 [湖北省选模拟 2023] 棋圣 alphago

Luogu P9542 [湖北省选模拟 2023] 棋圣 alphago

时间:2024-07-01 21:21:39浏览次数:12  
标签:棋圣 std int Luogu P9542 times 棋子 max operatorname

2023.08.19:修改了一处笔误。

手玩发现对于一颗生成树,如果存在至少一个点的度数 \(> 2\)(即不为链),那么肯定能使得所有棋子都在一条边的两个端点上。
因为有度数 \(> 2\) 的点的存在,这里就可以合并与其相连的点的棋子。

先考虑非链的情况的答案,记两部分棋子黑白棋子颜色分别为 \(c(a/b)(0/1)\)。
由两部分棋子在一条边上考虑到二分图。
若为二分图,则不管怎么走两部分棋子所在的颜色都是不同的,即两部分棋子最优情况也还是中间有一条边,答案为 \(w_{\max}\times (c(a)(0)\times c(b)(1) + c(a)(1)\times c(b)(0))\)。
若不为二分图,则图上肯定存在奇环,可以利用这个奇环分割开黑白棋子并把黑白棋子分别凑在一起,答案为 \(w_{\max}\times ((c(a)(0) + c(b)(0))\times (c(a)(1) + c(b)(1)))\)。

再来考虑链的情况。
手玩能发现最后棋子的位置需要满足 \(3\) 点:

  1. 在链上相邻的两个点操作完的距离 \(\le\) 两个点的初始距离,因为发现选取的空节点只存在两点之间或之外的情况,而距离变化分别为 \(-2\) 和不变。
  2. 在链上相邻的两个点不会在操作中调换顺序,证明与 1 相似。
  3. 在链上相邻的两个点操作完的距离与两个点的初始距离模 \(2\) 意义下同余,因为链也是个二分图。

考虑 DP,设 \(f_{i, l, r}\) 为到链上第 \(i\) 个点且这个点上有编号为 \([l, r]\) 的棋子的最大权值,不合法的值为 \(-\inf\)。
记 \(\operatorname{count}([l, r], [L, R])\) 为这 \(2\) 个区间的棋子能产生的配对数,\(\operatorname{dis}(x, y)\) 为这两个棋子在链上的距离。
转移分为 \(2\) 部分:

  • 从 \(i - 1\) 选的点与 \([l, r]\) 产生贡献,\(f_{i, l, r} = \max\limits_{L = 1}^{l - 1} ([\operatorname{dis}(l - 1, l)\equiv 1\pmod 2]\times (f_{i - 1, L, l - 1} + \operatorname{count}([L, l - 1], [l, r])\times w(i - 1, i)))\),可以在枚举的时候维护 \(\operatorname{count}\),单次 \(O(n)\)。
  • 从前面的点转移过来,但是不产生贡献,\(f_{i, l, r} = \max\limits_{j = i - \operatorname{dis(l, l - 1)}}^{i - 1}([i - j\equiv \operatorname{dis}(l - 1, l)\pmod 2]\times (\max\limits_{L = 1}^{l - 1} f_{j, L, l - 1}))\),但这样是 \(O(n^2)\) 的。
    发现对于每个 \(j\) 求的就是右端点为 \(l - 1\) 的最大值,可以预处理 \(g_{i, r} = \max\limits_{l = 1}^r f_{i, l, r}\),转移式便为 \(f_{i, l, r} = \max\limits_{j = i - \operatorname{dis(l, l - 1)}}^{i - 1}([i - j\equiv \operatorname{dis}(l - 1, l)\pmod 2]\times g_{j, l - 1})\),时间复杂度 \(O(n)\)。

时间复杂度 \(\mathcal{O}(n^4)\)。

#include<bits/stdc++.h>
const int N = 1e2 + 10;
int n, m, k;
std::vector<int> G[N];
int cx[N], cy[N];
int Gx[N * N], Gy[N * N], Gz[N * N];
int deg[N], deg_cnt[N];
int check_Case1() {
	for (int i = 1; i <= m; i++) {
		deg[Gx[i]]++, deg[Gy[i]]++;
	}
	for (int i = 1; i <= n; i++) {
		deg_cnt[deg[i]]++;
	}
	return deg_cnt[1] == 2 && deg_cnt[2] == n - 2;
}
int mcol[N];
void dfs(int u, int &flg) {
	for (auto v : G[u]) {
		if (mcol[v] == -1) {
			mcol[v] = mcol[u] ^ 1, dfs(v, flg);
		} else {
			flg &= mcol[u] != mcol[v];
		}
	}
}
int check_Case2() {
	for (int i = 1; i <= m; i++) {
		G[Gx[i]].push_back(Gy[i]), G[Gy[i]].push_back(Gx[i]);
	}
	memset(mcol, -1, sizeof(int) * (n + 1));
	int flg = 1;
	mcol[1] = 0, dfs(1, flg);
	return flg;
}
int cnt[2][2];
std::pair<int, int> c[N];
std::vector<std::pair<int, int> > Gc[N];
int dep[N], w[N];
int f[N][N][N], g[N][N];
int d[N], rd[N], ld[N];
int main() {
	scanf("%d%d%d", &n, &m, &k);
	for (int i = 1; i <= k; i++) {
		scanf("%d%d", &cx[i], &cy[i]);
	}
	for (int i = 1; i <= m; i++) {
		scanf("%d%d%d", &Gx[i], &Gy[i], &Gz[i]);
	}
	if (check_Case1()) {
		for (int i = 1; i <= m; i++) {
			Gc[Gx[i]].emplace_back(Gy[i], Gz[i]), Gc[Gy[i]].emplace_back(Gx[i], Gz[i]);
		}	
		int st = -1, ed = -1;
		for (int i = 1; i <= n; deg[i] == 1 && (st == -1 ? st = i : ed = i, 1), i++);
		for (int i = st, d = 1; d <= n; d++) {
			dep[i] = d;
			std::pair<int, int> v = dep[Gc[i][0].first] == 0 ? Gc[i][0] : Gc[i][1];
			i = v.first, w[d + 1] = v.second;
		}
		for (int i = 1; i <= k; i++) {
			c[i] = {cx[i], cy[i]};
		}
		std::sort(c + 1, c + k + 1, [](std::pair<int, int> a, std::pair<int, int> b) {
			return dep[a.first] < dep[b.first];
		});
		for (int i = 1; i < k; i++) {
			d[i] = dep[c[i + 1].first] - dep[c[i].first];
		}
		rd[k] = k;
		for (int i = k - 1; i; i--) {
			rd[i] = (d[i] & 1) ? i : rd[i + 1]; 
		}
		ld[1] = 1;
		for (int i = 2; i <= k; i++) {
			ld[i] = (d[i - 1] & 1) ? i : ld[i - 1];
		}
		memset(f, -0x3f, sizeof(f));
		memset(g, -0x3f, sizeof(g));
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= rd[1]; j++) {
				f[i][1][j] = 0, g[i][j] = 0;
			}
		}
		for (int i = 2; i <= n; i++) {
			for (int l = 2; l <= k; l++) {
				cnt[0][0] = cnt[1][0] = 0;
				int R = l - 1;
				for (int r = l; r <= rd[l]; r++) {
					cnt[c[r].second][0]++;
					if (d[R] & 1) {
						cnt[0][1] = cnt[1][1] = 0;
						for (int L = R; L >= ld[R]; L--) {
							cnt[c[L].second][1]++;
							f[i][l][r] = std::max(f[i][l][r], f[i - 1][L][R] + w[i] * (cnt[0][0] * cnt[1][1] + cnt[1][0] * cnt[0][1]));
						}
					}
					for (int j = i - d[R] > 0 ? i - d[R] : (((i - d[R]) & 1) ? 1 : 2); j < i; j += 2) {
						f[i][l][r] = std::max(f[i][l][r], g[j][R]);
					}
					g[i][r] = std::max(g[i][r], f[i][l][r]);
				}
			}
		}
		int ans = f[0][0][0];
		for (int i = 1; i <= n; i++) {
			for (int l = ld[k]; l <= k; l++) {
				ans = std::max(ans, f[i][l][k]);
			}
		}
		printf("%d\n", ans);
	} else if (check_Case2()) {
		for (int i = 1; i <= k; i++) {
			cnt[cy[i]][mcol[cx[i]]]++;
		}
		int mxz = 0;
		for (int i = 1; i <= m; mxz = std::max(mxz, Gz[i]), i++);
		printf("%d\n", mxz * (cnt[0][0] * cnt[1][1] + cnt[0][1] * cnt[1][0]));
	} else {
		for (int i = 1; i <= k; i++) {
			cnt[cy[i]][0]++;
		}
		int mxz = 0;
		for (int i = 1; i <= m; mxz = std::max(mxz, Gz[i]), i++);
		printf("%d\n", mxz * (cnt[0][0] * cnt[1][0]));
	}
	return 0;
}

标签:棋圣,std,int,Luogu,P9542,times,棋子,max,operatorname
From: https://www.cnblogs.com/rizynvu/p/18278859

相关文章

  • Luogu P6864 [RC-03] 记忆
    先考虑没有\(3\)操作该怎么做。对于当前字符串把其分成多组互不包含的括号的形式,即\((\cdots)()()\)这样,考虑经过\(1/2\)操作后对互不包含的括号组数\(b\)和答案\(v\)会产生什么影响。\(1\)操作,加上过后便会多上一组互不包含的括号,\(b\leftarrowb'+1\),同时这个......
  • [刷题笔记] Luogu P1612 [yLOI2018] 树上的链
    ProblemDescriptionDescription给定一棵有\(n\)个节点的树。每个节点有一个点权和一个参数。节点\(i\)的权值为\(w_i\),参数为\(c_i\)。\(1\)是这棵树的根。现在,对每个节点\(u\)(\(1\lequ\leqn\)),请在树上你找到最长的一条链\(v_1,v_2,\dotsv_m\),满足如下条件:......
  • [luoguP10608]双人游戏
    题目信息原题链接来源:[LGR-190]2024洛谷6月月赛IIDiv1T1/Div2T3题意长度为\(n\)的序列\(s\),其中只包含B,W和\(m\)个_。给定长度为\(m\)的序列\(O=[\langc_1,x_1\rang,\langc_2,x_2\rang,\cdots,\langc_m,x_m\rang](c_i\in\{\mathtt{R},\mathtt{M}\},s_{x_i}=\text{'_'......
  • [lnsyoj166/luoguP2822/NOIP2016提高组] 组合数问题
    题意原题链接给定\(n,m,k\),对于所有的\(0\lei\len,0\lej\lemin\{i,m\}\),有多少对\((i,j)\)满足\(k|(^i_j)\)sol在解决组合数问题时,若遇到\(n,m\le2000\)的情况,可以使用递推法(杨辉三角)来进行\(O(n^2)\)的预处理,再\(O(1)\)直接调用递推法求组合数\[(^n_m)=(^{n-1}_m)+(......
  • [lnsyoj284/luoguP2286/HNOI2004]宠物收养场
    题意原题链接每个宠物和领养人有一个对应的特点值\(a\),当领养人过多时,若添加一个特点值为\(a_p\)的宠物,则查询收养店中特点值最接近\(a_p\),为\(a_q\)的领养人(\(<a_p\)的值优先),将答案累加\(|a_q-a_p|\),然后删除该领养人,否则在收养店中添加一个领养人。反之亦然。求最终的答案\(......
  • [lnsyoj98/luoguP1403]约数研究
    题意原题链接求\(1\simn\)的约数个数和sol直接算很困难,考虑换一个角度求\(1\simn\)的约数个数和,等价于求\(1\simn\)分别是范围内几个数的约数对于第\(i\)个值,在\(1\simn\)中,存在\(i,2\cdoti,3\cdoti,\cdots,k\cdoti\),共\(\lfloor\frac{n}{i}\rfloor\)因此,最终......
  • [lnsyoj118/luoguP3369]普通平衡树
    题意维护一个数据结构,要求支持插入,删除,根据排名查数,根据数查排名,查询前驱,查询后继\(6\)个操作sol考虑到后四个查询的操作,会发现使用二叉搜索树(BST)完全可以实现为了完成这四个操作,需要在每个节点记录\(3\)个值:\(key\)表示当前节点的数\(cnt\)表示当前节点的数的个数(为了......
  • [DP] [倍增优化] Luogu P1081 [NOIP2012 提高组] 开车旅行
    [NOIP2012提高组]开车旅行题目描述小\(\text{A}\)和小\(\text{B}\)决定利用假期外出旅行,他们将想去的城市从$1$到\(n\)编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市\(i\)的海拔高度为\(h_i\),城市\(i\)和城市\(j\)之间的距......
  • Luogu P1784 数独 [ 模板 ] / P1074 靶形数独 题解 [ 蓝 ] [ 深搜 ] [ 剪枝 ] [ 卡常
    数独模板,靶形数独卡了2h,再也不想写数独了。思路显然是对每个格子进行枚举,类似八皇后的方法去做,朴素方法是由\((1,1)\)到\((9,9)\)遍历过去。优化我们人在做数独时,会优先选择已填格数多的行、列、区域,这样可以保证尝试次数少。同样,这一点在本题中也可以应用,但是有两......
  • [lnsyoj283/luoguP1856/IOI1998]矩形周长Picture
    题意原题链接求几个矩形的周长并sol遇到几何图形的**并,都可以使用扫描线思想来解决观察易得,与x轴平行的边和与y轴平行的边相互独立,因此可以扫描两次,分别计算并累加以与x轴平行的边为例:假设有一条平行于x轴的直线从下到上扫描,每当遇到一条边时,若这条边是某个矩形的下边,则在......