首页 > 其他分享 >2022.12.22 动态规划练习

2022.12.22 动态规划练习

时间:2022-12-22 17:22:06浏览次数:70  
标签:22 int text 练习 样例 电塔 81 节点 2022.12

依旧是被题目折磨的一天,能想出状态表示,但是在状态计算时不太会想。

P1040 [NOIP2003 提高组] 加分二叉树

题目描述

设一个 \(n\) 个节点的二叉树 \(\text{tree}\) 的中序遍历为\((1,2,3,\ldots,n)\),其中数字 \(1,2,3,\ldots,n\) 为节点编号。每个节点都有一个分数(均为正整数),记第 \(i\) 个节点的分数为 \(d_i\),\(\text{tree}\) 及它的每个子树都有一个加分,任一棵子树 \(\text{subtree}\)(也包含 \(\text{tree}\) 本身)的加分计算方法如下:

\(\text{subtree}\) 的左子树的加分 \(\times\) \(\text{subtree}\) 的右子树的加分 \(+\) \(\text{subtree}\) 的根的分数。

若某个子树为空,规定其加分为 \(1\),叶子的加分就是叶节点本身的分数。不考虑它的空子树。

试求一棵符合中序遍历为 \((1,2,3,\ldots,n)\) 且加分最高的二叉树 \(\text{tree}\)。要求输出

  1. \(\text{tree}\) 的最高加分。

  2. \(\text{tree}\) 的前序遍历。

输入格式

第 \(1\) 行 \(1\) 个整数 \(n\),为节点个数。

第 \(2\) 行 \(n\) 个用空格隔开的整数,为每个节点的分数。

输出格式

第 \(1\) 行 \(1\) 个整数,为最高加分(\(Ans ≤ 4,000,000,000\))。

第 \(2\) 行 \(n\) 个用空格隔开的整数,为该树的前序遍历。

样例 #1

样例输入 #1

5
5 7 1 2 10

样例输出 #1

145
3 1 2 4 5

提示

数据规模与约定

对于全部的测试点,保证 \(1 \leq n< 30\),节点的分数是小于 \(100\) 的正整数,答案不超过 \(4 \times 10^9\)。

思路

状态表示:\(f[i][j]\) 表示从节点 \(i\) 到 \(j\) 构成的树的分数集合,而我们要求的是最大值。
状态计算:我们考虑 \(f[i][j]\) 且 \(i < j\),特别的 \(i = j\) 时,\(f[i][j] =\) 节点值。对于 \(i\) 至 \(j\) 的节点构成的树,我们枚举其根节点 \(k\),则 \(f[i][j] = max(f[i][k - 1] * f[k + 1][j] + f[k][k])\),并且在计算过程中用 \(root[i][j]\) 记录最大值对应的根节点索引 \(k\)。

C++代码

#include <bits/stdc++.h>
using namespace std;
const int N = 50, M = 20010, mod = 998244353;
typedef pair<int, int> PII;
typedef long long LL;

int n;
LL f[N][N], root[N][N]; // 从节点i到j成树的最大加分

void print(int l, int r)
{
	if(l > r) return;
	printf("%lld ", root[l][r]);
	if(l == r) return;
	print(l, root[l][r] - 1);
	print(root[l][r] + 1, r);
}

int main ()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++)
	{
		scanf("%lld", &f[i][i]);
		f[i][i - 1] = 1; // 左为空
		f[i + 1][i] = 1; // 右为空
		root[i][i] = i;
	}
	for(int len = 2; len <= n; len ++) // 枚举节点长度
	{
		for(int i = 1; i + len - 1 <= n; i ++) // 枚举起点
		{
			int j = i + len - 1; // 计算终点
			for(int k = i; k <= j; k ++) // 枚举根
			{
				if(f[i][j] < f[i][k - 1] * f[k + 1][j] + f[k][k])
				{
					f[i][j] = f[i][k - 1] * f[k + 1][j] + f[k][k];
					root[i][j] = k;
				}
			}
		}
	}
	printf("%lld\n", f[1][n]);
	print(1, n);
    return 0;
}

P4933 大师

题目背景

建筑大师最近在跟着数学大师 ljt12138 学数学,今天他学了等差数列,ljt12138 决定给他留一道练习题。

题目描述

ljt12138 首先建了 \(n\) 个特斯拉电磁塔,这些电塔排成一排,从左到右依次标号为 \(1\) 到 \(n\),第 \(i\) 个电塔的高度为 \(h[i]\)。

建筑大师需要从中选出一些电塔,然后这些电塔就会缩到地下去。这时候,如果留在地上的电塔的高度,从左向右构成了一个等差数列,那么这个选择方案就会被认为是美观的。

建筑大师需要求出,一共有多少种美观的选择方案,答案模 \(998244353\)。

注意,如果地上只留了一个或者两个电塔,那么这种方案也是美观的。地上没有电塔的方案被认为是不美观的。

同时也要注意,等差数列的公差也可以为负数。

输入格式

第一行一个正整数 \(n\)。

第二行 \(n\) 个非负整数,第 \(i\) 个整数是第 \(i\) 个电塔的高度 \(h[i]\)。

输出格式

输出一个整数,表示美观的方案数模 \(998244353\) 的值。

样例 #1

样例输入 #1

8
13 14 6 20 27 34 34 41

样例输出 #1

50

样例 #2

样例输入 #2

100
90 1004 171 99 1835 108 81 117 141 126 135 144 81 153 193 81 962 162 1493 171 1780 864 297 180 532 1781 189 1059 198 333 1593 824 207 1877 216 270 225 1131 336 1875 362 234 81 288 1550 243 463 1755 252 406 261 270 279 288 1393 261 1263 297 135 333 872 234 881 180 198 81 225 306 180 90 315 81 81 198 252 81 297 1336 1140 1238 81 198 297 661 81 1372 469 1132 81 126 324 333 342 81 351 481 279 1770 1225 549

样例输出 #2

11153

提示

设 \(v\) 为最高的电塔高度。

对于前 \(30\%\) 的数据,$n \le 20 $。

对于前 \(60\%\) 的数据,\(n \le 100\),\(v \le 2 \times 10^3\)。

对于另外 \(20\%\) 的数据,所有电塔的高度构成一个等差数列。

对于 \(100\%\) 的数据,\(n \le 10^3\),\(v \leq2 \times 10^4\)。

思路

状态表示:\(f[i][j]\) 表示以第 \(i\) 个数为结尾,\(j\) 为方差构成的等差数列的集合,我们要求的是方案数量。
状态计算:考虑 \(f[i][j]\) 第 \(i\) 个数为结尾的数列的前一个数 \(j\),则有 \(f[i][h[i] - h[j]] = f[j][h[i] - h[j]] + 1\)。
注意方差可能为负数,差值的绝对值最大为 \(20000\),本题目数组开大一点即可。

C++代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1010, M = 20010, mod = 998244353;
typedef pair<int, int> PII;

int n;
int h[N];
int f[N][2 * M]; // f[i]表示以h[i]为结尾的等差为j的数列个数
int s[N];

int main ()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++)
		scanf("%d", &h[i]);
	for(int i = 1; i <= n; i ++)
		s[i] = 1; // 只取h[i]
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 1; j < i; j ++)
		{
			f[i][h[i] - h[j] + M] = (f[i][h[i] - h[j] + M] + (f[j][h[i] - h[j] + M] + 1)) % mod;
			s[i] = (s[i] + f[j][h[i] - h[j] + M] + 1) % mod;
		}
	}
	int ans = 0;
	for(int i = 1; i <= n; i ++) ans = (ans + s[i]) % mod;
	printf("%d\n", ans);
    return 0;
}

标签:22,int,text,练习,样例,电塔,81,节点,2022.12
From: https://www.cnblogs.com/Cocoicobird/p/16999130.html

相关文章

  • 12.22
    今日内容1.django中间件的三个了解方法2.基于django中间件的功能设计3.cookie与session4.django操作cookie5.django操作session1.django中间件的三个了解方法1.proc......
  • Win10和WSL Ubuntu 22.04.1 SSH远程连接
    openssh-server配置安装ssh服务器在Ubuntu20.04.1LTS子系统安装openssh-server。在Ubuntu子系统中,执行一下命令:sudoaptinstallopenssh-server编辑远程登录配置信息......
  • HTML-表单-2022-12-22
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>登录注册</title></head><body><h1>注册</h1><!--表单formaction提交的位置,可以是网站,......
  • 20221222. k8s - 拉勾教育【归档】
    参考资料Kubernetes中文官网Kubernetes中文文档KubernetesAPI命令行工具(kubectl)前言背景2020年学习后,一直没有总结,期间也没有实际使用过,直到2022......
  • 【221222-3】已知:a+b=2,且b>0 问:当1/(2|a|)+|a|/(b)取最小值时,a=?
    ......
  • 【221222-2】已知:5x平方y平方+y的四次方=1 求:x平方+y平方的最小值?
    ......
  • 20221215 2. k8s 介绍
    kubernetes与dockerswarm对比DockerSwarmKubernetes开发者Docker公司谷歌发布年份20132014ControllerManagerMasterStorageVolumesPers......
  • 20221220 7. Service
    简介Service|Kubernetes可以通过Deployment来创建一组Pod来提供具有高可用性的服务。虽然每个Pod都会分配一个单独的PodIP,然而却存在如下两问题:PodIP仅仅是集群内......
  • 20221219 6. 资源控制器
    简介ControllerManager由kube-controller-manager和cloud-controller-manager组成,是Kubernetes的大脑,它通过apiserver监控整个集群的状态,并确保集群处于预期......
  • 20221218 5. pod 进阶
    资源清单格式Pod|Kubernetes资源清单有5个顶级的字段组成:apiVersion、kind、metadata、spec、statusapiVersion:group/apiversion#如果没有给定group名称,那么默......