思路:
常规的暴力会超时,所以就用对选择的技能数进行优化
1.二分查找:
从最低攻击力(也就是所有选择的技能序列中加最低攻击力的一个)进行二分查找,例如7表示这些选择的技能中最低也要加7点攻击力。
选择一个最低攻击力mid,对所有技能进行遍历:
如果可以选择的技能数大于等于M,则说明这个最低攻击力可以更高。
如果小于M,则要降低攻击力。
可能会出现最优值可以选择大于M技能数的情况(即这个值可选技能数大于M,而这个值+1后可选技能数小于M),这种情况放在后面进行讨论。
'''
arr[i][0]表示第i种技能的初始攻击力
arr[i][1]表示选择升级一次的降低攻击力
'''
def Binary_Search(mid):
global N,M,arr
rnt=0
for i in range(1,N+1):
if arr[i][0] < mid: continue
rnt+=(arr[i][0]-mid)//arr[i][1]+1
if rnt>=M : return True #可以更大
return False #太大了
left=1
right=1000000
while(left<=right):
mid=(left+right)//2
if Binary_Search(mid):
left=mid+1
else:
right=mid-1
2.进行选择
此时,我们将最低攻击力等于right(最低攻击力不一定是mid,可能是mid-1,但是一定是right,因为right最低)的情况先不考虑(优先选择更好的)-也就是对应出现最优值可以选择大于M个技能数的情况。
最后,将剩余的次数*right(最低攻击力)即可。
for i in range(1,N+1):
if arr[i][0]<=right:continue
temp=(arr[i][0]-right)//arr[i][1]+1
end=arr[i][0]-arr[i][1]*(temp-1)
if end==right:temp-=1
ans+=(2*arr[i][0]-(temp-1)*arr[i][1])*temp//2
ret-=temp
import sys
input=sys.stdin.readline
N,M=map(int,input().split())
arr=[[]]
for i in range(N):
arr.append(list(map(int,input().split())))
left,right=1,10000000
def Binary_Search(mid):
global N,M,arr
rnt=0
for i in range(1,N+1):
if arr[i][0] < mid: continue
rnt+=(arr[i][0]-mid)//arr[i][1]+1
if rnt>=M : return True #可以更大
return False #太大了
mid=0
while left<=right:
mid=(left+right)//2
if Binary_Search(mid):
left=mid+1
else:
right=mid-1
ret=M
ans=0
for i in range(1,N+1):
if arr[i][0]<=right:continue
temp=(arr[i][0]-right)//arr[i][1]+1
end=arr[i][0]-arr[i][1]*(temp-1)
if end==right:temp-=1
ans+=(2*arr[i][0]-(temp-1)*arr[i][1])*temp//2
ret-=temp
print(ans+ret*right)