首页 > 其他分享 >P8736 [蓝桥杯 2020 国 B] 游园安排

P8736 [蓝桥杯 2020 国 B] 游园安排

时间:2024-05-26 20:13:36浏览次数:31  
标签:cnt return int P8736 元素 蓝桥 -- 2020 dp

P8736 [蓝桥杯 2020 国 B] 游园安排

一、问题简析

本题考点是 最长上升子序列

二分查找

根据模板,我们需要实现一个二分查找,找到 dp 中首个大于等于 A[i] 的元素。比较的规则是字典序

// 按字典序比较A[a]和A[b],return A[a] < A[b] 
bool cmp(const int &a, const int &b)
{
	int mmin = min(cnt[a], cnt[b]);
	for (int i = 0; i < mmin; ++i)
		if (A[a][i] > A[b][i])    return false;
		else if (A[a][i] < A[b][i])    return true;
	if (cnt[a] < cnt[b])    return true;
	else    return false;
}

// 二分查找dp[i]中首个不小于A[key]的位置 
int search(int key)
{	
	int L = 1, R = ptr;
	while (L <= R)
	{
		int M = (R - L) / 2 + L;
		if (cmp(dp[M], key))
			L = M + 1;
		else
			R = M - 1;
	}
		
	return L;
}

哨兵元素

在模板中,需要将 dp 都初始化为 INF。此出,按字典序,INFZzzzzzzzzzzz。原因有两点:1、名字都是由一个大写字母若干个小写字母构成;2、名字最长为10位

记录子序列

模板中,dp 仅记录尾元素。在讨论元素 A[i] 时,二分找到了它在 dp 中的位置 j,一定可以确定 dp[j - 1] 是它的前一个元素的下标。因此,我们只要记录每一个元素的前一个元素。最后,从最长上升子序列的尾元素开始,倒着找到所有元素。


Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int MAX = 1e6 + 5;
int dp[MAX], pre[MAX], cnt[MAX], ptr;  // ptr -- 元素个数 
// dp[i] -- 长度i的序列的尾元素下标; pre[i] -- 下标i的元素的前一个元素的下标; cnt[i] -- 下标i的元素的长度 
char A[MAX][15], s; // A[i] -- 下标i的元素; s -- 输入 

// 按字典序比较A[a]和A[b],return A[a] < A[b] 
bool cmp(const int &a, const int &b)
{
	int mmin = min(cnt[a], cnt[b]);
	for (int i = 0; i < mmin; ++i)
		if (A[a][i] > A[b][i])    return false;
		else if (A[a][i] < A[b][i])    return true;
	if (cnt[a] < cnt[b])    return true;
	else    return false;
}

// 二分查找dp[i]中首个不小于A[key]的位置 
int search(int key)
{	
	int L = 1, R = ptr;
	while (L <= R)
	{
		int M = (R - L) / 2 + L;
		if (cmp(dp[M], key))
			L = M + 1;
		else
			R = M - 1;
	}
		
	return L;
}

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	char ch;
	while (true)
	{
		ch = getchar();
		if (ch == EOF)    break;
		
		if (ch >= 'A' && ch <= 'Z')    ++ptr; // 将输入元素分开 
		
		A[ptr][cnt[ptr]++] = ch;
	}
	
	sprintf(A[0], "Zzzzzzzzzzzz"); // 相当于INF 
	cnt[0] = 12;
	for (int i = 1; i <= ptr; ++i)
	{
		int ans = search(i);
		
		dp[ans] = i;
		pre[i] = dp[ans - 1]; // 记录A[i]的前一个元素下标 
	}
	
	int p = search(0);
	p = dp[p - 1];     // 首个小于INF的元素A[p],即最长子序列的尾元素 
	stack<int> ans;
	while (p != 0)     // 逆序找到子序列中的所有元素 
	{
		ans.push(p);
		p = pre[p];
	}
	
	while (!ans.empty())
	{
		printf("%s", A[ans.top()]);
		ans.pop();
	}
	
	return 0;
}

标签:cnt,return,int,P8736,元素,蓝桥,--,2020,dp
From: https://www.cnblogs.com/hoyd/p/18214210

相关文章

  • 蓝桥杯备赛——DP【python】
    一、小明的背包1试题链接:https://www.lanqiao.cn/problems/1174/learning/问题描述输入实例52016253851533输出示例37问题分析这里我们要创建一个DP表,DP(i,j)表示处理到第i个物品时消耗j体积。这样我们在输入数据时可以直接进行操作。对于每一个dp[i][j]我......
  • 题解:P6880 [JOI 2020 Final] オリンピックバス
    一个比较重要的性质:反转的边要在最短路上才会有贡献。我们可以先跑一遍最短路,记录下整颗最短路树,然后暴力的对每一条边进行判断,反转。我们建正反图各两个,分别以\(1\),\(n\)为起点。\(n\),\(1\)为终点。然后对每个图跑最短路,记录下最短路树。若不反转任何一条边,则答案为\(1\)......
  • 2020综合知识
    本题考查高速缓存的基础知识。高速缓冲存储器是存在于主存与CPU之间的一级存储器。主存储器存取速度一直比中央处理器操作速度慢得多,使中央处理器的高速处理能力不能充分发挥,整个计算机系统的工作效率受到影响。高速缓冲存储器可用来缓和中央处理器利主存储器之间速度不匹配的......
  • P8655 [蓝桥杯 2017 国 B] 发现环
    原题链接题解有点像拓扑排序拓扑排序怎么做来着?首先找老祖节点对不对?老祖节点有什么特性?入度为零而在无向图中,我们把叶子节点看成老祖节点,它们有什么特性?连接的边只有一条code#include<bits/stdc++.h>usingnamespacestd;vector<int>G[100005];intcon[100005]={......
  • P8765 [蓝桥杯 2021 国 AB] 翻转括号序列
    本文参考博客[蓝桥杯2021国AB]翻转括号序列(线段树上二分)一、问题简析线段树+二分初步分析令(的值为1,)的值为-1,则对于序列\(a_La_{L+1}a_{L+2}...a_R\),其为合法序列的条件为\[\begin{cases}\sum_{n=L}^R{a_n}=0\\\forall~k\in[L,R],\sum_{n=L}^k{a_n}\ge......
  • 蓝桥杯-数三角(ac代码时间复杂度分析)
    问题描述小明在二维坐标系中放置了(n)个点,他想在其中选出一个包含三个点的子集,这三个点能组成三角形。然而这样的方案太多了,他决定只选择那些可以组成等腰三角形的方案。请帮他计算出一共有多少种选法可以组成等腰三角形?输入格式输入共(n+1)行。第一行为一个正整数(......
  • 免费,Python蓝桥杯等级考试真题--第10级(含答案解析和代码)
    Python蓝桥杯等级考试真题–第10级一、选择题1、已知s='Hello!’,下列说法正确的是?()A.s[1]对应的字符是’H’B.s[2]对应的字符是’l’C.s[-1]对应的字符是’o’D.s[3]对应的字符是’o’答案:B解析:s[1]对应字符是‘e’;s[2]对应字符是‘l’;s[-1]对应字符是‘e!;s[3]......
  • 蓝桥楼赛第30期-Python-第二天赛题 题解
    楼赛第30期Python模块大比拼解析网页元素目标本次挑战,我们需要使用Python访问软科世界大学排行榜来获取首页30所学校的信息。为避免目标网站的内容发生变化,我们使用保存之后的网页进行实验。链接如下:https://labfile.oss.aliyuncs.com/courses/4070/rank2021.h......
  • 蓝桥杯-班级活动
    题目描述小明的老师准备组织一次班级活动。班上一共有(n)名((n)为偶数)同学,老师想把所有的同学进行分组,每两名同学一组。为了公平,老师给每名同学随机分配了一个(n)以内的正整数作为id,第(i)名同学的id为(a_i)。老师希望通过更改若干名同学的id使得对于任意......
  • 蓝桥杯-合并数列
    小明发现有很多方案可以把一个很大的正整数拆成若干正整数的和。他采取了其中两种方案,分别将它们列为两个数组{a1,a2,...,an}和{b1,b2,...,bm}。两个数组的和相同。定义一次合并操作可以将某数组内相邻的两个数合并为一个新数,新数的值是原来两个数的和。小明想通过若干......