转跳到内容

每 日 算 法 挑 战 【第1期】


推荐贴

1 小时前, Mr.K 018 说道:

这个引理我觉得很重要,怎么打怪就变成了怎么往slot里塞东西,也就是说要把一个个怪“摊”到这个怪血量之前的那些slot上

然后,我觉得可以从控0次血开始一点点向上摊,先摊派控0次的,之后是控1次,直到无穷;如果发现有哪个怪摊不完所有的控血+击杀,就撤销这个怪的所有摊派(这个怪就不打了)

我似乎知道我智障在哪了:mx040:

 

A.sort() #升序排列
slotNum = A[-1] #拿到A里最大的元素值,作为总的格子数

#计算各元素需要补刀数量
B = empty_like(A) #记录各元素需要补刀数
freeSpaceList = [] #记录可用划水位
index = 0

for value in range(1, slotNum + 1):
	#遍历A中的所有元素值,耗时O(|A| + max(A))
	if A[index] > value:
		#空,加入到划水位
		freeSpaceList.append(value)
	else:
		#A中值为value的第一个元素
		B[index] = 0 #不需要补刀
		index = index + 1 #移动到下一个元素
		while A[index] == value:
			#A中值为value的重复元素
			if freeSpaceList:
				#还有空余划水位可用
				lastFreeSpace = freeSpaceList.pop()
				B[index] = value - lastFreeSpace #计算补刀数
			else:
				#没空位我有什么办法嘛,这个人头彻底放弃了
				B[index] = -1
			index = index + 1 #移动到下一个元素


#开始填格子
tempLastIdx = 0 #记录目前预计最后一个人头的位置
tempFreeSpaceSize = 0 #记录目前可以操作的空间
score = 0 #记录目前的得分

for value in range(0, max(B) + 1):
	#从最好拿人头的(0补刀)开始,逐渐增加补刀数
	for index in range(len(B)-1, -1, -1):
		#倒序遍历所有元素
		if B[index] == value:
			#可以考虑拿人头了
			if tempLastIdx < index:
				#更新最后一个人头的位置
				tempFreeSpaceSize = tempFreeSpaceSize + (index - tempLastIdx) #因为最后一个人头位置增加了,增加了更多的操作空间
				tempLastIdx = idx
			if tempFreeSpaceSize > B[index] + 1:
				#有位置补刀+收人头
				tempFreeSpaceSize = tempFreeSpaceSize - (B[index] + 1)
				score = score + 1
			else:
				#没位置了,再往前也是一样要补刀的个数,一样不会有位置的
				break

基本算是按照py的语法写的,应该稍微改一些细节就能直接跑了,不过感觉应该有不少优化空间,这大循环写的我看着就疼

,由yhz012修改
链接到点评
5 分钟前, yhz012 说道:

我似乎知道我智障在哪了:mx040:

 


A.sort() #升序排列
slotNum = A[-1] #拿到A里最大的元素值,作为总的格子数

#计算各元素需要补刀数量
B = empty_like(A) #记录各元素需要补刀数
freeSpaceList = [] #记录可用划水位
index = 0

for value in range(1, slotNum + 1):
	#遍历A中的所有元素值,耗时O(|A| + max(A))
	if A[index] > value:
		#空,加入到划水位
		freeSpaceList.append(value)
	else:
		#A中值为value的第一个元素
		B[index] = 0 #不需要补刀
		index = index + 1 #移动到下一个元素
		while A[index] == value:
			#A中值为value的重复元素
			if freeSpaceList:
				#还有空余划水位可用
				lastFreeSpace = freeSpaceList.pop()
				B[index] = value - lastFreeSpace #计算补刀数
			else:
				#没空位我有什么办法嘛,这个人头彻底放弃了
				B[index] = -1
			index = index + 1 #移动到下一个元素


#开始填格子
tempLastIdx = 0 #记录目前预计最后一个人头的位置
tempFreeSpaceSize = 0 #记录目前可以操作的空间
score = 0 #记录目前的得分

for value in range(0, max(B) + 1):
	#从最好拿人头的(0补刀)开始,逐渐增加补刀数
	for index in range(len(B)-1, -1, -1):
		#倒序遍历所有元素
		if B[index] == value:
			#可以考虑拿人头了
			if tempLastIdx < index:
				#更新最后一个人头的位置
				tempFreeSpaceSize = tempFreeSpaceSize + (index - tempLastIdx) #因为最后一个人头位置增加了,增加了更多的操作空间
				tempLastIdx = idx
			if tempFreeSpaceSize > B[index] + 1:
				#有位置补刀+收人头
				tempFreeSpaceSize = tempFreeSpaceSize - (B[index] + 1)
				score = score + 1
			else:
				#没位置了,再往前也是一样要补刀的个数,一样不会有位置的
				break

基本算是按照py的语法写的,应该稍微改一些细节就能直接跑了

呃,嗯……

算法没问题没错,但是最大血量可以到1e8(盯

这个算法都到这了,我觉得优化一下没啥问题,因为我们不在乎每一个slot被用来干啥了,只关心有多少slot可以用,这样的话是能把存储量压到1e5的

,由Mr.K 018修改

Mr.K 018和寒幼藏在半夜盗取清禾的传国玉玺时,无意中挖出了清禾祖传的3DS,卖出手后获得了奖励8节操

链接到点评
17 分钟前, Mr.K 018 说道:

呃,嗯……

算法没问题没错,但是最大血量可以到1e8(盯

:mx005:是的,这里我看着就疼,填格子的部分倒是可以先把B构造成key-value对,然后根据value sort一下然后能把下面的循环时间压到O(|A|),上面的循环我还得考虑下……

 

某种意义上第一个求补刀数可以删掉,但是这样就要增加后面循环的量了……

后面的循环直接

A.sort()
A.reverse() #降序

usedSlot = {}
step = 0 #补刀数
slotNum = A[0] #总格子数

while A and slotNum >= step + 1:
	#A非空就继续填格子,或者所有格子填满了
	for a in A:
		#倒序遍历
		if a - step not in usedSlot:
			#有空位
			if slotNum > step + 1:
				#能补过来
				usedSlot = usedSlot + {a - step} #人头占位
				A.remove(a) #考虑过了,之后不用再看了
				score = score + 1
				slotNum = slotNum - (step + 1)
			else:
				#补不过来了,之后肯定都补不过来了
				return score
		else:
			#没空位,留着下一轮继续判断
			pass

 

,由yhz012修改
链接到点评
3 小时前, yhz012 说道:

 

 


	for index in range(len(B)-1, -1, -1):
		#倒序遍历所有元素

 

我觉得这里应该是正序遍历

(讲道理引理2的B和C是什么我没看懂)

,由随性而为修改

随性而为路过听到路过酱的歌声,不小心被路过的鸡仔绊倒,受到了路过酱的赔偿金2节操

链接到点评
2 小时前, yhz012 说道:

usedSlot = {}

这个usedSlot我觉得不用保存成集合,我们可以只知道当前有多少个slot可以用就能进行下去了。

(删掉了一些错误信息)

我们只要保存每个血量段有多少个slot可以用,比如10血到20血的分段我有3个slot可以用,20-30没有,30-35有1个这样等等

分段的依据是怪,比如上例中这么分段的原因会是因为有10血、20血、30血、35血的怪。控血+打怪的时候,要优先选取离当前血量近的段,比如打35血怪要优先选取30-35段的那一个slot这样。

这样一来,程序的复杂度应该就降到n^2了?我肉眼看是n^2

,由Mr.K 018修改
链接到点评
13 小时前, 随性而为 说道:

我觉得这里应该是正序遍历

(讲道理引理2的B和C是什么我没看懂)

引理2的B和C都是和题目中的A一样的数组

其中B是A的子集,同时B中的每一个元素都可以在C中找到一个对应,这个对应要满足 b >= c

此外C中的元素全部唯一,没有重复元素

 

你可以理解为B是早苗的人头实际来源,C是早苗拿人头的回合

 

13 小时前, Mr.K 018 说道:

控血+打怪的时候,要优先选取离当前血量近的段,比如打35血怪要优先选取30-35段的那一个slot这样。

这点我同意,但是我头疼的是30-35有1个意味着我实际上是有,比如说30, 31, 32, 34, 35这样的一组数据的如果这时候我有一个重复35的要控血到33,我需要控2次就好了

但是如果我原来是30, 32, 33, 34, 35,我就需要控4次了……

感觉还是卡在了哪里……

 

啊我理解了,我实际上保存key-value对就好了,key是连续空白最后的位置,value是连续空白的长度

比如我写一个数组,里面存放这个key-value对,slot[(lastPos, size)]

这样我倒序的话,每次使用最大key的key-value对,消耗掉相应的value并降低key,value归零就丢掉这个kv对就完了

因为kv对是连续的,所以最坏被分割出(N+1)个kv对

 

判断对应slot是否被用了就直接找第一个大于index的key,然后看key-value是不是小于value就完了

,由yhz012修改
链接到点评
6 小时前, yhz012 说道:

引理2的B和C都是和题目中的A一样的数组

其中B是A的子集,同时B中的每一个元素都可以在C中找到一个对应,这个对应要满足 b >= c

此外C中的元素全部唯一,没有重复元素

 

你可以理解为B是早苗的人头实际来源,C是早苗拿人头的回合

 

这点我同意,但是我头疼的是30-35有1个意味着我实际上是有,比如说30, 31, 32, 34, 35这样的一组数据的如果这时候我有一个重复35的要控血到33,我需要控2次就好了

但是如果我原来是30, 32, 33, 34, 35,我就需要控4次了……

感觉还是卡在了哪里……

如果是1,2,4,5,5,105,215,218,218,211,211

我觉得一开始的代码后面的循环这样改比较好,可能会解决这个问题吧(错了错了,还没改好)(改不动了,不会改)

for value in range(0, max(B) + 1):
	#从最好拿人头的(0补刀)开始,逐渐增加补刀数
	for index in range(0,len(B)-1):
		#正序遍历所有元素
		if B[index] == value:
			#可以考虑拿人头了
			tempFreeSpaceSize = tempFreeSpaceSize + (index - tempLastIdx) #因为最后一个人头位置增加了,增加了更多的操作空间
			tempLastIdx = index
			if tempFreeSpaceSize > B[index] + 1:
				#有位置补刀+收人头
				tempFreeSpaceSize = tempFreeSpaceSize - (B[index] + 1)
				score = score + 1
   	tempFreeSpaceSize=0
    	tempLastIdx=0

 

,由随性而为修改

随性而为收和谐资源时被小萝莉围观良心发现失去-2节操

链接到点评
1 小时前, 随性而为 说道:

如果是1,2,4,5,5,105,215,218,218,211,211

我觉得一开始的代码后面的循环这样改比较好,可能会解决这个问题吧(错了错了,还没改好)(改不动了,不会改)


for value in range(0, max(B) + 1):
	#从最好拿人头的(0补刀)开始,逐渐增加补刀数
	for index in range(0,len(B)-1):
		#正序遍历所有元素
		if B[index] == value:
			#可以考虑拿人头了
			tempFreeSpaceSize = tempFreeSpaceSize + (index - tempLastIdx) #因为最后一个人头位置增加了,增加了更多的操作空间
			tempLastIdx = index
			if tempFreeSpaceSize > B[index] + 1:
				#有位置补刀+收人头
				tempFreeSpaceSize = tempFreeSpaceSize - (B[index] + 1)
				score = score + 1
   	tempFreeSpaceSize=0
    	tempLastIdx=0

 

我决定用后面的这个代码了,因为一开始为了求B数组实在是太疼了1e8级别的跑起来真的太疼了

链接到点评
×
×
  • 新建...

重要消息

为使您更好地使用该站点,请仔细阅读以下内容: 使用条款