第一行输入一个整数
代表同学数量。
第二行输入
个整数
代表每一位同学的身高。
输出一个整数,代表最少需要出列的同学数量。
8 186 186 150 200 160 130 197 200
4
在这个样例中,有且仅有两种出列方式,剩下的同学分别为
和
。
# 等回头用二分查找实现一遍 def get_max_up_arr(arr, count_num): arr_line = [1]*count_num for i in range(count_num): for j in range(i): if arr[j] < arr[i]: arr_line[i] = max(arr_line[i], arr_line[j]+1) return arr_line while True: try: num_count = input() arr = list(map(int,raw_input().split(' '))) left_up_arr = get_max_up_arr(arr, num_count) right_up_arr = get_max_up_arr(arr[::-1], num_count)[::-1] least_num = num_count - max([ i+j-1for i,j in zip(left_up_arr,right_up_arr)]) print least_num except: break
超时只通过40%, 但感觉算法思路应该是对的 while True: try: N = int(input()) nums = list(map(int, input().split())) f_1 = [] # 每个位置最长左子列长度 f_2 = [] # 每个位置最长右子列长度 for i in range(N): f_1.append(1) f_2.append(1) for j in range(1, N): for k in range(0, j): if nums[j] > nums[k]: f_1[j] = max(f_1[j], f_1[k]+1) if nums[N-1-j] > nums[N-1-k]: f_2[N-1-j] = max(f_2[N-1-j], f_2[N-1-k]+1) max_q = 1 for i in range(N): max_q = max(max_q, (f_1[i] + f_2[i])-1) print(N - max_q) except: break
动态规划和利用单调队列的思想大神们已经讲得很多,本人上传一版自己注释的代码,希望可以对还是不理解此题的朋友有一定帮助
#二分搜索定位函数,自己写此函数,也可用已有库bisect #搜索元素val在nums中的定位,返回的定位位置i,需满足: #nums[:i]中所有元素都 < val, nums[i:]中所有元素都 >= val def binary(nums, val): l = 0 r = len(nums)-1 while l < r: mid = (l + r) // 2 if nums[mid] == val: return mid elif nums[mid] > val: #为满足开头说的搜索条件和目的,此处一定不能写成 r = mid - 1 r = mid else: l = mid + 1 return r #计算以每个位置为中心,得到的左侧可以满足单调要求的人数(不包括自己) def count(nums): #单调递增队列queue,初始为nums[0] #每个位置的左侧满足要求的人数count(默认为0) queue = [nums[0]] count = [0 for _ in range(len(nums))] #从1开始遍历即可,因为第一个位置nums[0]左侧无人,count一定为0 for i in range(1, len(nums)): #当nums[i]大于此位置前出现的最大值时,左侧满足要求的人数即为len(queue) if nums[i] > queue[-1]: count[i] = len(queue) queue.append(nums[i]) #否则,进行二分搜索定位并覆盖旧值 #在单调递增队列中的定位位置下标 即为其左侧满足要求的人数 else: location = binary(queue, nums[i]) queue[location] = nums[i] count[i] = location return count while True: try: n = int(input()) nums = list(map(int, input().split())) assert(n == len(nums)) left_count = count(nums)#得到每个位置左侧满足要求的人数 right_count = count(nums[::-1])[::-1]#得到每个位置右侧满足要求的人数 max_peple = 1#最大人数初始为1 for i in range(len(left_count)): #当前可组成的最大人数,由于前面计算的左右侧人数不包括自己,需再+1 cur_peple = 1 + left_count[i] + right_count[i] if cur_peple > max_peple: max_peple = cur_peple print(n - max_peple) except: break
import bisect def lss(seq): temp, res = [float("inf")]*len(seq), [] for e in seq: pos = bisect.bisect_left(temp, e) temp[pos] = e res.append(pos+1) return res while True: try: n, heights = int(input()), list(map(int, input().split())) lm = lss(heights) rm = lss(heights[::-1])[::-1] print(n-max(map(sum, zip(lm, rm)))+1) except: break
while True: try: n = int(input()) A = list(map(int, input().split())) left = [0] * n for i in range(1, n): for j in range(i): if A[j] < A[i] and left[j] + 1 > left[i]: left[i] = left[j] + 1 right = [0] * n for i in range(n - 2, -1, -1): for j in range(n - 1, i, -1): if A[j] < A[i] and right[j] + 1 > right[i]: right[i] = right[j] + 1 ans = 0 for i in range(n): if left[i] > 0 and right[i] > 0: if left[i] + right[i] + 1 > ans: ans = left[i] + right[i] + 1 res = n - ans print(res) except: break
import bisect def shouldRemoveLeft(team: list) -> list: cur_team = [team[0]] removed = [0] * len(team) i = 1 while i < len(team): x = team[i] pos = bisect.bisect(cur_team, x) removed[i] = removed[i-1] + len(cur_team) - pos cur_team = cur_team[:pos] cur_team.append(x) i += 1 return removed def numsOfPeopleOutOfTheTeam(team: list) -> int: if not team&nbs***bsp;len(team) < 3: return 0 dp_left = shouldRemoveLeft(team) dp_right = shouldRemoveLeft(team[::-1])[::-1] ans = float('inf') for i in range(len(team)): ans = min(dp_left[i] + dp_right[i], ans) return ans if __name__ == "__main__": import sys i = [] for line in sys.stdin: i.append(line) ans = numsOfPeopleOutOfTheTeam(i[1].strip().split()) print(ans)
基本思想是计算最长递增子数列,可以使用两种方法。第一种 left_most() 函数使用动态规划搜索,时间复杂度为 O(N^2)。第二种 left_most_binary() 使用了二分法搜索,可以将时间复杂度降低至 O(NlogN)。中心思想是设置一个排序数列 dp 来存放 arr 里的数,用二分法搜索每个数 arr[i] 插入 dp 的位置,如果该数需要被插入 dp 末尾位置,就增加 dp 的长度。对每个 arr[i]来说,dp 的长度就是 该数左边的最长递增子数列的值。注意 dp 里的数值并不是该递增子数列。
import bisect def left_most(arr): # time: O(n^2), space: O(n) ans = [1]*len(arr) for i in range(len(arr)): for j in range(i): if arr[j]<arr[i] and ans[j]+1>ans[i]: ans[i] = ans[j]+1 return ans def left_most_binary(arr): # time: O(nlogn), space: O(n) ans = [1]*len(arr) dp = [] for i in range(len(arr)): index = bisect.bisect_left(dp, arr[i]) if index==len(dp): dp.append(arr[i]) else: dp[index] = arr[i] ans[i] = len(dp) return ans while True: try: n = int(input()) if not n: break h = list(map(int, input().split(' '))) left = left_most_binary(h) right = left_most_binary(h[::-1])[::-1] ans = max([left[i]+right[i]-1 for i in range(n)]) print (n-ans) except: break
while True: try: N, num = int(input()), list(map(int, input().split())) dp1, dp2, dp3 = [1]*N, [1]*N, [] for x in range(1, N): for i in range(0, x): if num[i] < num[x]: dp1[x] = max(dp1[x], dp1[i] + 1) for x in range(N-1, -1, -1): for i in range(N-1, x, -1): if num[i] < num[x]: dp2[x] = max(dp2[x], dp2[i] + 1) for x in range(0,N): dp3.append(N+1-dp1[x]-dp2[x]) print(min(dp3)) except: break
def left_max(list): """计算出i这个人,包含自己,在左边符合人数的个数""" res = [1] * len(list) for i in range(len(list)): for j in range(i): if list[j] < list[i] and res[j] + 1 > res[i]: res[i] = res[j] + 1 return res def right_max(list): """计算出i这个人,包含自己,在右边符合人数的个数""" res = [1] * len(list) for i in range(len(list))[::-1]: for j in range(i+1,len(list)): if list[j] < list[i] and res[j] + 1 > res[i]: res[i] = res[j] + 1 return res while True: try: n = int(input()) result = list(map(int,input().split())) left = left_max(result) right = right_max(result) sum_list = [] for i in range(len(left)): sum_list.append(left[i] + right[i]) print(n - (max(sum_list) - 1)) except:
def LittleMan(length, highLs): leftLs = [1 for i in range(length)] rightLs = [1 for i in range(length)] # [1, 1, 1, 2, 2, 1, 3, 4] for i in range(1, length): maxValue = 1 for j in range(0, i): if highLs[i] > highLs[j]: if leftLs[j] + 1 > maxValue: maxValue = leftLs[j] + 1 leftLs[i] = maxValue (3739)# [3, 3, 2, 3, 2, 1, 1, 1] for i in range(length-2, -1, -1): maxValue = 1 for j in range(i+1, length): if highLs[i] > highLs[j]: if rightLs[j] + 1 > maxValue: maxValue = rightLs[j] + 1 rightLs[i] = maxValue allLs = list() for i in range(length): allLs.append(rightLs[i] + leftLs[i] - 1) max_val = max(allLs) return length - max_val if __name__ == "__main__": while True: try: n=int(input()) s=list(map(int,input().split())) res = LittleMan(n, s) print(res) except: break
def updown(h): res = [1 for i in range(len(h))] for i in range(len(h)): for j in range(i): if h[i] > h[j] and res[i] < res[j] + 1: res[i] = res[j] + 1 ''' 死活过不了。。。复杂度一样 但是估计是用了max函数,所以增加了运行时间。。。 if h[i] > h[j]: res[i] = max(res[i], res[j] + 1) ''' return res while True: try: n = int(input()) hArray = list(map(int, input().split())) resleft = updown(hArray) resright = updown(hArray[::-1])[::-1] res = [] for i in range(len(hArray)): res.append(resleft[i] + resright[i] - 1) print(n - max(res)) except: break
import bisect #动态规划获得最大递增自序列,时间复杂度O(n*n) # def ascMax(l, dp): # dp += [1] # for i in range(1, len(l)): # tmp = 0 # for j in range(0, i): # if l[j] < l[i]: # tmp = max(dp[j], tmp) # dp += [tmp + 1] #二分法获取最大递增子序列,时间复杂度O(nlogn) def ascMax(l, dp): dp += [1] b = [float('inf') for i in range(len(l))]#初始化b数组为无穷大 b[0] = l[0](1844)#第一个元素自己就是最大递增子序列 for i in range(1, len(l)): pos = bisect.bisect_left(b, l[i]) b[pos] = l[i] dp += [pos + 1] while True: try: N = int(input()) H = list(map(int, input().split(' '))) dp_1, dp_2 = [], [] ascMax(H, dp_1) ascMax(H[::-1], dp_2) dp = [] for i in range(0, N): dp += [dp_1[i] + dp_2[N-i-1] - 1] print(N - max(dp)) except: break
if l[j]<l[i] and ans[j]+1>ans[i]: ans[i]=ans[j]+1
# 每个人的左边出现的最多人(输出左_最长递增子序列) def left_max(l):#l为站成一排的同学序列 ans=[1]*len(l) for i in range(len(l)):# 每个人的游标(从前往后) for j in range(i):# 这个人前面每个人的游标 if l[j]<l[i] and ans[j]+1>ans[i]: ans[i]=ans[j]+1 return ans # 1 1 1 2 2 1 3 4 # 每个人的右边出现的最多人(输出右_最长递增子序列) def right_max(l): ans=[1]*len(l) for i in range(len(l)-1,-1,-1):# 每个人的游标(从后往前) for j in range(i+1,len(l)):# 这个人后面每个人的游标 if l[j]<l[i] and ans[j]+1>ans[i]: ans[i]=ans[j]+1 return ans # 3 3 2 3 2 1 1 1 while True: try: N=int(input())(1177)#8 tall_li_str=input().split() tall_li_int=[int(v) for v in tall_li_str]#[186,186,150,200,160,130,197,200] left_li=left_max(tall_li_int) right_li=right_max(tall_li_int) sum_li=[]#left_li和right_li加和,可以得到每个人如果是中间那个人的话,合唱队最长是多少(自己算两遍) for i in range(len(left_li)): sum_li.append(left_li[i]+right_li[i]) print(N-max(sum_li)+1)#题中问的是最少去几人,也就是总人数减去合唱队最多人数 # 另外加和时自己算了两遍,还得再减去一遍 except: break
import bisect def deal(l,res): b = [float('inf')]*len(l) b[0] = l[0] res = res+[1] for i in range(1,len(l)): pos =bisect.bisect_left(b,l[i]) b[pos]=l[i] res += [pos+1] return res def main(n,s): n = int(n) s = list(map(int,s.split())) dp1, dp2=[], [] dp1 =deal(s,dp1) dp2 =deal(s[::-1],dp2)[::-1] return n-max(map(sum,zip(dp1,dp2)))+1 while 1: try: print(main(input(),input())) except: exit()
import sys def lsi(values): L = len(values) def check(vs): index = 0 L0 = [] D = [-1] + [2000000000 for i in range(L)] for v in vs: begin = 0 end = index # 二分查找 while True: if end - begin <= 1: break mid = (begin + end) / 2 if D[mid] >= v: end = mid else: begin = mid for tmp in (begin, end): if D[tmp] < v: index = max(tmp + 1, index) D[tmp + 1] = min(D[tmp + 1], v) L0.append(index) return L0 L0 = check(values) values.reverse() L1 = check(values) maxim = 0 for i in range(L): maxim = max(L0[i] + L1[L - i - 1] -1, maxim) return max(max(L0), max(L1), maxim) while True: N = sys.stdin.readline().strip() if not N: break values = [int(i) for i in sys.stdin.readline().strip().split(' ')] print len(values) - lsi(values)
def get_index(nums,target): # 返回列表中不小于目标元素的索引 low,high=0,len(nums) # 左开右闭区间 while low<high: mid=(low+high)//2 if nums[mid]<target: low=mid+1 else: high=mid return low def increase_lis(l): sorted_l = [float('inf') for _ in range(len(l))] #巧妙的实现去重,可以理解为去重有序数组 res,sorted_l[0] = [1],l[0] for i in range(1,len(l)): pos=get_index(sorted_l,l[i]) res.append(pos+1) sorted_l[pos] = l[i] return res while True: try: n=int(input()) a=list(map(int,input().strip().split())) dp_L=increase_lis(a) dp_R=increase_lis(a[::-1])[::-1] max_value=max([dp_L[i]+dp_R[i]-1 for i in range(n)]) print(n-max_value) except: break参照为啥要起名字那位同学,有序数组初始化为定长是精髓,实现插入时自动去重
用 Python 搞动态规划太容易超时超内存了,用 PyPy 经过 array
优化才跑通:
from array import array def max_inc_sub(nums=None): dp = [1] * len(nums) for i in range(1, len(nums)): for j in range(i): if nums[i] > nums[j]: dp[i] = max(dp[i], dp[j] + 1) return dp while True: try: total = int(input()) heights = array("I", [int(h) for h in input().split()]) inc1 = max_inc_sub(heights) inc2 = max_inc_sub(heights[::-1])[::-1] _max = 0 for x1, x2 in zip(inc1, inc2): _max = max(_max, x1 + x2) print(total - _max + 1) # print(total - max([x1 + x2 for x1, x2 in zip(inc1, inc2)]) + 1) except Exception as e: break