27.方向标

news/2024/10/21 11:59:18/

题目

描述

一位木匠收到了一个木制指示牌的订单。每块木板必须与前一块垂直对齐,要么与前一个箭头的基部对齐,要么与相反的一侧对齐,在那里用特制的螺钉固定。两块木板必须重叠。木匠将设计师发送的草图编码成了一个整数序列,但该序列不能确定唯一的模型,他已经把原始草图扔掉了。这看起来像是一个微不足道的任务,但对他来说却是一个巨大的拼图。

序列(有1 + N个元素)将(N)个箭头从底部到顶部的位置进行编码。第一个元素是底部箭头左侧的位置。剩余的N个元素定义了箭头头部的起始位置,从底部到顶部:第i个元素是第i个箭头基部的位置。例如,左侧和右侧的两个标志可以通过2 6 5 1 4进行编码。

由于木板必须与前一块垂直对齐(要么与前一个箭头的基部对齐,要么与相反的一侧对齐),如果序列是2 6 5 1 4 3,第五个箭头可以用一个螺钉固定(在任何一个描绘的标志上)在1(指向右边)或4(指向左边),箭头基座在3。

如果序列是2 3 1,第二个箭头只能用一个螺钉固定在3上,指向左边,因为连续的木板必须重叠。

所有的箭头头部都是相似的,设计师告诉木匠,它们的基部站在不同的垂直线上,底部箭头的左侧也是如此,共同形成1..(N +1)的排列。这就是为什么木匠忽略了细节,只是写下了排列(例如2 6 5 1 4 3)。

给定木匠写下的数字序列,计算可以制作的指示牌数量。由于数字可能非常大,你必须对2147483647取模。序列的第二个整数始终大于第一个整数(底部的箭头总是指向右边)。

输入

第一行有一个整数N,第二行包含从1到N + 1的整数的排列。同一行中的整数之间用一个空格分隔。

输出

输出一行,其中包含给定排列描述的不同标志的数量(对2147483647取模)。

注意

1 ≤ N ≤ 2000


题意

  1. 只需关注箭头长方形部分的头部(靠近三角形)和底部。
  2. 箭头从下往上依次放置。
  3. 第一个箭头的头部和底部题目已经确定,并且头部下标一定大于底部。
  4. 上面的箭头的底部,必须等于下面的箭头的底部,或者等于下面的箭头的头部。
  5. 相邻两个箭头需要有重叠部分,即不能错开。

由此推知

  1. 对于当下箭头而言,上一块箭头的头部和底部很重要。
  2. 上面的箭头的底部可能有多种放法
  3. 题目就是要我们输出有多少种不同的情况。
  4. 要求对输出结果%2147483647。
     

思路(动态规划)

我们用数组s[N+1]记录每一块木块的头部下标。注意:s[0]存储第一块的底部下标

第一步:确定dp数组以及下标的含义

我们需要一个二维dp数组,dp[i][j]表示第i个箭头以j为底时的方案数。

第二步:确定递推公式

3种情况:

  • 第i块的头比上一块的头和尾都小
    dp[i][max(s[i - 1], s[j])] += dp[i - 1][s[j]];
  • 第i块的头比上一块的头和尾都大
     dp[i][min(s[i - 1], s[j])] += dp[i - 1][s[j]]; 
  • 第i块的头在上一块头尾之间
    dp[i][s[i - 1]] += dp[i - 1][s[j]];
    dp[i][s[j]] += dp[i - 1][s[j]];

第三步:dp数组初始化

第一个箭头只有一种放的方法:dp[1][s[1]]=1

遍历每一个箭头时,令dp[i][s[i]]=1,以本身头部为底时为一。结果记得减一

第四步:确定遍历顺序

外循环从第二个箭头开始,内循环遍历上一个箭头所有可能底部。
如果dp[i-1][j]>0,说明上一个箭头存在以该底部放置的方案,方可进入递推。

第五步:结果处理

遍历dp[N],把每一个底部的方案加起来就是结果。


注意事项

  1. long long存储数据。
  2. 最后结果和每次dp变化之后和要取模

C++完整代码

改改再提交乐学,有查重!!

#include <iostream>
#include <vector>
using namespace std;const int MOD = 2147483647;int main() {int N;cin >> N;vector<long long> s(N + 1);for (int i = 0; i <= N; i++) {cin >> s[i];}vector<vector<long long>> dp(N + 1, vector<long long>(2001, 0));dp[1][s[0]] = 1;dp[1][s[1]] = 1;for (int i = 2; i <= N; i++) {for (int j = i - 2; j >= 0; j--) {dp[i][s[i]] = 1;if (dp[i - 1][s[j]] != 0) {if (s[i] > s[i - 1] && s[i] > s[j]) {dp[i][min(s[i - 1], s[j])] += dp[i - 1][ s[j]];dp[i][min(s[i - 1], s[j])] %= MOD;}else if (s[i] <s[i - 1] && s[i] < s[j]) {dp[i][max(s[i - 1], s[j])] += dp[i - 1][s[j]];dp[i][max(s[i - 1], s[j])] %= MOD;}else if ((s[i] <= s[i - 1] && s[i] >= s[j]) || (s[i] >= s[i - 1] && s[i] <= s[j])) {dp[i][s[i - 1]] += dp[i - 1][s[j]];dp[i][s[i - 1]] %= MOD;dp[i][s[j]] += dp[i - 1][s[j]];dp[i][s[j]] %= MOD;}}}}long long res = 0;for (int i = 0; i <= 2000; i++) {res += dp[N][i];res %= MOD;}cout << res-1 << endl;return 0;
}


http://www.ppmy.cn/news/1097801.html

相关文章

Java基础09 —— 字符序列--String、StringBuilder、StringBuffer区别及其方法介绍

Java基础09 —— 字符序列 字符串类型 字符与字符串 字符类型(char)是Java中的基本数据类型&#xff0c;占2个字节16位&#xff0c;默认值是 ‘\u0000’ 。字符是用单引号引住的单个符号. // 字符 char c A; //单引号 char cA 65; //数字 char c1 \u8888; //Unicode码 S…

嵌入式IDE(2):KEIL中SCF分散加载链接文件详解和实例分析

在上一篇文章IAR中ICF链接文件详解和实例分析中&#xff0c;我通过I.MX RT1170的SDK中的内存映射关系&#xff0c;分析了IAR中的ICF链接文件的语法。对于MCU编程所使用的IDE来说&#xff0c;IAR和Keil用得比较多&#xff0c;所以这一篇文章就来分析一下Keil的分散文件.scf(scat…

java中将List数据平均切分成N份

话不多说&#xff0c;直接上代码&#xff0c;直接用 public static <T> List<List<T>> averageList(List<T> source, int n) {List<List<T>> ret new ArrayList<List<T>>();int number source.size() / n;int remainder so…

SAP Business One二次开发:解锁潜力,实现定制化需求

作为广泛应用于中小型企业的企业资源计划&#xff08;ERP&#xff09;软件&#xff0c;SAP Business One提供了众多强大工具&#xff0c;助力企业管理与优化业务流程。然而&#xff0c;对于某些特定的业务需求和流程而言&#xff0c;标准SAP Business One可能无法完美满足。为应…

应用人脸活体检测技术,保障刷脸支付安全畅通

如今&#xff0c;人脸识别已经走进了我们生活中的方方面面&#xff0c;拿起手机扫脸付账&#xff0c;扫描人脸完成考勤&#xff0c;刷脸入住酒店纷纷便利了我们的生活。而人脸识别里一项必不可少的技术就是人脸活体检测&#xff0c;即AI不但要确定这是“你”&#xff0c;还需要…

使用本地mysql+linux实现mysql主从同步

1.配置linux 保证linux已经安装好了mysql1.1修改该linux配置文件 vim /etc/my.cnf1.2重启linux的mysql systemctl restart mysqld1.3使用账户密码登录linux中的mysql,查看是否配置成功 mysql> show master status;若显示有FIile和Posttion就表示注linux的主节点配置成功…

Mysql--事务

事务 开始之前&#xff0c;让我们先想一个场景&#xff0c;有的时候&#xff0c;为了完成某个工作&#xff0c;需要完成多种sql操作 比如转账 再比如下单 第一步 我的账户余额减少 第二步 商品的库存要减少 第三步 订单表中要新增一项 事务的本质&#xff0c;就是为了把多个操…

ntpd 和ntpdate 的区别

ntpd 和 ntpdate 都是用于进行网络时间同步的工具&#xff0c;但在功能和使用方式上有所不同。 ntpd&#xff08;Network Time Protocol daemon&#xff09;是 NTP 守护进程&#xff0c;用于在计算机网络中持续同步系统时钟与全球标准时间。ntpd 可以在计算机启动时自动启动&a…