概述
题目描述
n 位同学站成一排,音乐老师要请其中的 n−k 位同学出列,使得剩下的 k 位同学排成合唱队形。
合唱队形是指这样的一种队形:设 k 位同学从左到右依次编号为 1,2, … ,k,他们的身高分别为 t1,t2, … ,tk,则他们的身高满足 t1<⋯<ti>ti+1> … >tk(1≤i≤k)。
你的任务是,已知所有 n 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
共二行。
第一行是一个整数 n(≤n≤100),表示同学的总数。
第二行有 n 个整数,用空格分隔,第 i 个整数 ti(130≤ti≤230)是第 i 位同学的身高(厘米)。
输出格式
一个整数,最少需要几位同学出列。
输入输出样例
输入
8
186 186 150 200 160 130 197 220
输出
4
说明/提示
对于 50% 的数据,保证有 n≤20。
对于全部的数据,保证有 n≤100。
前置知识:线性dp,最长上升子序列的nlogn优化,二分查找(和洛谷的导弹拦截都是这类题型的模板题
分析:
- 最少几个同学出列,其实就是求解最多几个同学能组成满足条件的序列
- 根据题意这个序列可以是一部分(完全严格上升或严格下降子序列)也可以是两部分(前面严格上升后面严格下降)
- 我们可以用ans1存上升部分的长度(ans1[i]表示到第i个数能形成的最长上升序列的长度,ans2类似),up存上升序列,ans2存下降部分,down存下降部分
- 两个ans都是在序列能变长时等于前面一个ans+1,不能变长就等于前面一个ans
- 最后将ans1和ans2打包求和就行
上AC代码
def check(l, obj, key): # 这个列表是从一个开始生成的,所以不能用bisect函数来简单书写。多传入参数是为了加快python的查找速度
"""不相等时要右边那一位"""
i, j = 0, l-1
while i < j:
m = i+j >> 1
if obj[m] == key: # 严格上升子序列里相等不用进行任何操作
return m
elif obj[m] > key:
j = m
else:
i = m+1
return i
n = int(input())
a = list(map(int, input().split()))
up = [a[0]]
down = [a[-1]]
ans1 = [1]*n
ans2 = [1]*n
for i in range(1, n):
if a[i] > up[-1]:
ans1[i] = ans1[i-1]+1
up.append(a[i])
else:
ans1[i] = ans1[i-1]
up[check(ans1[i], up, a[i])] = a[i]
if a[n-1-i] > down[-1]: # 倒着取少写一个二分,即都是求严格上升子序列了
ans2[n-1-i] = ans2[n-i]+1
down.append(a[n-1-i])
else:
ans2[n-1-i] = ans2[n-i]
down[check(ans2[n-1-i], down, a[n-1-i])] = a[n-1-i]
print(n-max([i+j-1 for i, j in zip(ans1, ans2)]))
最后
以上就是细心玉米为你收集整理的二分+线性dp模板题:洛谷《合唱队形》的python题解的全部内容,希望文章能够帮你解决二分+线性dp模板题:洛谷《合唱队形》的python题解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复