我是靠谱客的博主 细心玉米,最近开发中收集的这篇文章主要介绍二分+线性dp模板题:洛谷《合唱队形》的python题解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题目描述

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优化,二分查找(和洛谷的导弹拦截都是这类题型的模板题

分析:

  1. 最少几个同学出列,其实就是求解最多几个同学能组成满足条件的序列
  2. 根据题意这个序列可以是一部分(完全严格上升或严格下降子序列)也可以是两部分(前面严格上升后面严格下降)
  3. 我们可以用ans1存上升部分的长度(ans1[i]表示到第i个数能形成的最长上升序列的长度,ans2类似),up存上升序列,ans2存下降部分,down存下降部分
  4. 两个ans都是在序列能变长时等于前面一个ans+1,不能变长就等于前面一个ans
  5. 最后将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题解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部