• 【Codeforces1263F_CF1263F】Economic Difficulties(图论_动态规划)


    题目

    Codeforces 1263F

    翻译

    好久没做英语大阅读了qwq。

    题目名:经济难题

    描述

    贝兰宫的供电网络由两张电网组成:主电网和备用电网。宫殿中的导线是用贵金属制造的,所以卖掉一些是个好主意。

    每张电网(主电网和备用电网)有一个根结点(标号为 (1) )。其他所有结点都从根结点获取电力。每个结点到根有且只有一条路径。并且,两张电网都恰好有 (n) 个不会把电力继续向下输送的结点。

    换句话说,每张电网都是一个恰好有 (n) 叶子的有根树,根的标号是 (1) 。两棵树的结点标号互相独立,且两棵树的结点之间不会相连。

    宫殿中有 (n) 个用电设备。每个设备连接主电网的一个结点和备用电网的一个结点。用电设备只连接不会把电力继续向下输送的结点(即树的叶子)。每一个叶子恰好连接一个用电设备。

    在这个例子中,主电网(上方的树)有 (6) 个结点,备用电网(下方的树)有 (4) 个结点。有 (3) 个用电设备,用蓝色数字编号。保证整个供电网络(两个电网和 (n) 个用电设备)可以用如下方式展示(就像上图中的一样):

    • 主电网是上方的树,导线从上向下连接;
    • 备用电网是下方的树,导线从下向上连接;
    • 用电设备在两棵树之间水平排成一排,从左到右编号依次为 (1)(n)
    • 结点之间的导线互不相交。

    形式化地,对于每一棵树,存在一种从 (1) 号点开始的 DFS 序,叶子按照连接用电设备 (1,2,dots,n) 的顺序访问(首先是连接了 (1) 号设备的叶子,然后是连接了 (2) 号设备的叶子,以此类推)。

    毕斯内斯曼 商人想卖掉(删掉)最多的导线,使得每个用电设备仍然能被至少一个电网(主电网或备用电网)供电。换句话说,在主电网或备用电网中,每个设备应该至少存在一条到根结点的路径,并且这条路径只包含该电网的结点。

    输入

    第一行包含一个整数 (n(1leq nleq 1000)) —— 宫殿中用电设备的数量。

    下一行包含一个整数 (a(1+nleq a leq 1000+n)) —— 主电网的结点数。

    下一行包含 (a-1) 个整数 (p_i(1leq p_ileq a))(p_i) 表示主电网中有一条导线连接 (p_i) 号结点和 (i+1) 号结点。

    下一行包含 (n) 个整数 (x_i) —— 第 (i) 个设备在主电网中连接的结点编号。

    下一行包含一个整数 (b(1+nleq b leq 1000+n)) —— 备用电网的结点数。

    下一行包含 (b-1) 个整数 (q_i(1leq q_ileq b))(q_i) 表示备用电网中有一条导线连接 (q_i) 号结点和 (i+1) 号结点。

    下一行包含 (n) 个整数 (y_i) —— 第 (i) 个设备在备用电网中连接的结点编号。

    保证每个电网都是一棵有 (n) 个叶子的树,每个叶子恰好连接一个设备。并且保证每棵树存在一种从 (1) 号点开始的 DFS 序,按照连接到的设备编号的顺序访问每个叶子。

    输出

    输出一个整数 —— 在保证所有设备都能供电的情况下最多能删掉的导线数量。

    分析

    我感觉很多不会这道题的人都是没看到 DFS 序那个条件 …… (比如某 s 姓选手)

    删掉某棵树中的一条边时,无法供电的设备一定是这条边的子树中所连接的设备,也就是一个设备的区间。

    由此能得到一个重要的性质:对于主电网,一个 极长的 不由它供电的区间 ([l,r]) (即 (l-1)(r+1) 如果存在均由主电网供电)对答案的贡献是一定的,与 ([1,l-1))((r+1,n]) 是否由主电网供电无关。对备用电网也是如此。用 (w_{0/1,l,r}) 表示 ([l,r]) 这段是不用主电网 / 备用电网供电的一个极长区间时,最多能删掉多少条边而不影响其他设备的电力供应。然后就可以直接 DP :

    [f_i=max_{j=0}^{i-1}(f_j+max(w_{0,j+1,i},w_{1,j+1,i})) ]

    考虑 (w_{0,l,r}) 怎么计算。枚举 (l) ,然后递推计算每一个 (r) 。和 ([l,r)) 相比,([l,r]) 多删去的一定是 从 (r) 往上的一条链。为了让 (l-1) 不断电,这条链的末端不能高于 (mathrm{lca}(l-1,r)),同理也不能高于 (mathrm{lca}(r,r+1)) 。事实上链的末端就是这两个 lca 中较低的一个,不可能有已经删过的,因为 ([l,r)) 的方案中保证了 (r) 一定能供电,所以这一条链上删掉的点不会高于 (mathrm{lca}(r-1,r)) 。具体可以画图和参考代码理解。

    代码

    #include <cstdio>
    #include <cstring> 
    #include <algorithm>
    #include <vector>
    using namespace std;
     
    namespace zyt
    {
    	const int N = 1e3 + 10, P = 2e3 + 10, B = 15;
    	int n, a, b, x[P], fa[B][P], dep[P], w[2][N][N];
    	vector<int> g[P];
    	void dfs(const int u)
    	{
    		dep[u] = dep[fa[0][u]] + 1;
    		for (int i = 1; i < B; i++)
    			fa[i][u] = fa[i - 1][fa[i - 1][u]];
    		for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it++)
    		{
    			int v = *it;
    			dfs(v);
    		}
    	}
    	int lca(int a, int b)
    	{
    		if (!a || !b)
    			return 1;
    		if (dep[a] < dep[b])
    			swap(a, b);
    		for (int i = B - 1; i >= 0; i--)
    			if (dep[fa[i][a]] >= dep[b])
    				a = fa[i][a];
    		if (a == b)
    			return a;
    		for (int i = B - 1; i >= 0; i--)
    			if (fa[i][a] != fa[i][b])
    				a = fa[i][a], b = fa[i][b];
    		return fa[0][a];
    	}
    	void solve(const int p)
    	{
    		int m;
    		scanf("%d", &m);
    		for (int i = 1; i <= m; i++)
    			g[i].clear();
    		for (int i = 2; i <= m; i++)
    			scanf("%d", fa[0] + i), g[fa[0][i]].push_back(i);
    		dfs(1);
    		for (int i = 1; i <= n; i++)
    			scanf("%d", x + i);
    		for (int i = 1; i <= n; i++)
    		{
    			for (int j = i; j <= n; j++)
    			{
    				int l = lca(x[j], x[i - 1]), l2 = lca(x[j], x[j + 1]);
    				if (dep[l] < dep[l2])
    					swap(l, l2);
    				w[p][i][j] = w[p][i][j - 1] + dep[x[j]] - dep[l];
    			}
    		}
    	}
    	int dp[N];
    	int work()
    	{
    		scanf("%d", &n);
    		solve(0), solve(1);
    		for (int i = 0; i < n; i++)
    			for (int j = i + 1; j <= n; j++)
    				dp[j] = max(dp[j], dp[i] + max(w[0][i + 1][j], w[1][i + 1][j]));
    		printf("%d", dp[n]);
    		return 0;
    	}
    }
    int main()
    {
    	return zyt::work();
    }
    
  • 相关阅读:
    linux_ext4恢复超级块.txt
    bayaim_Centos7.6_mysql源码5.7-多my.cnf_20190424.txt
    bayaim_Centos7.6_mysql源码5.7-multi_20190424.txt
    zhy2_rehat6_mysql04
    zhy2_rehat6_mysql03
    Neo4j安装,入门到深入了解完整教程
    程序员千万不要裸辞,对你没有任何好处
    减薪是变相的裁员所以我还是走吧
    python正则表达式匹配中文日期时间
    python用正则表达式匹配字符串里的日期
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/12396817.html
Copyright © 2020-2023  润新知