解題想法:
開四個串列儲存從左到右以及又到左的的奇偶差和數字和
再開兩個字典儲存兩邊奇偶差的數字出現的位置(set是看有那些數字出現過
然後從兩個set挑出左右奇偶差可以配對的
之後在從中用二分搜配出可以的
但我不知為何我第0.1.13比測資都不會過 答案都比正確值大
我覺得可能是從右側挑出來的執筆左側挑出來的位置靠左導致的,所以加了判斷
但還是一樣QQ
a,s = map(int,input().split())
d = list(map(int,input().split()))
co = [-1 if i%2==0 else 1 for i in d]#判斷數字是奇偶
maxs = 0#最大值
stco,enco = {co[0]:[0]},{co[-1]:[0]}#記錄底下的數字出現的位置
stcoset,encoset = {co[0]},{co[-1]}#記錄總共出現那些數字(奇偶相加) #set型態
sttotal,entotal = [d[0]],[d[-1]]
ram = [co[0],co[-1]]#暫存當前奇偶和
for i in range(0,a-1):#記錄從左右分別數去的奇偶數量和 從左右分別加總得和 以及每個數字出現的位置
ram = [ram[0]+co[i+1],ram[1]+co[a-i-2]]#目前左右分別往內的奇偶數加總
if ram[0] not in stcoset:#這個數字記錄過了嗎 沒的話就幫他開個字典位置有的話就直接去存
stco[ram[0]] = [i+1]
stcoset.add(ram[0])
else:stco[ram[0]].append(i+1)
if ram[1] not in encoset:
enco[ram[1]] = [i+1]#因為算從右邊過來的總和時排列順序沒調成原本的d的順序 所以就跟從左邊開始的順序一樣底下好計算
encoset.add(ram[1])
else:enco[ram[1]].append(i+1)
sttotal.append(sttotal[i] + d[i+1])
entotal.append(entotal[i] + d[a-i-2])
def loop():
global maxs
matchs = []
for i in stcoset:
if i*-1 in encoset:matchs.append(i)#這組數字可以用
for i in matchs:
stkey = sorted(stco[i])
enkey = sorted(enco[i*-1])
#print(stkey,enkey,i)
for o in stkey:
nowb = len(enkey)-1#二分搜
nows = 0
#print(stkey,enkey,o,nows,nowb)
if sttotal[o] + entotal[enkey[nows]] > s:continue#若最小的都爆掉了就沒後續
elif sttotal[o] + entotal[enkey[nowb]] <= s:#若最大的都沒有爆掉了就沒後續
if (a -enkey[nowb]) >o:#目前位置在o的右邊
if sttotal[o] + entotal[enkey[nowb]]>maxs:maxs = sttotal[o] + entotal[enkey[nowb]]
continue
else:
while (a -enkey[nowb]) >o:nowb -= 1
while nowb>=nows:
ram = (nowb+nows)//2#目前在哪個位置
ram2 = sttotal[o] + entotal[enkey[ram]]
if ram2 == s:#剛好一樣大
maxs = s
return
if ram2 > s:nowb = ram - 1 # 總和超過,縮小上界
else:
maxs = max(maxs, ram2) # 更新最大值
nows = ram + 1 # 總和符合條件,提高下限
loop()
print(maxs)#目前問題:有時候會比正確答案大
二更:
我發現我一開始貼的些低級錯誤我<>打反
我改了下
現在90%了
但問題還是一樣 會比較大 0.13還是沒過
以下是改的程式碼
a,s = map(int,input().split())
d = list(map(int,input().split()))
co = [-1 if i%2==0 else 1 for i in d]#判斷數字是奇偶
maxs = 0#最大值
stco,enco = {co[0]:[0]},{co[-1]:[0]}#記錄底下的數字出現的位置
stcoset,encoset = {co[0]},{co[-1]}#記錄總共出現那些數字(奇偶相加) #set型態
sttotal,entotal = [d[0]],[d[-1]]
ram = [co[0],co[-1]]#暫存當前奇偶和
for i in range(0,a-1):#記錄從左右分別數去的奇偶數量和 從左右分別加總得和 以及每個數字出現的位置
ram = [ram[0]+co[i+1],ram[1]+co[a-i-2]]#目前左右分別往內的奇偶數加總
if ram[0] not in stcoset:#這個數字記錄過了嗎 沒的話就幫他開個字典位置有的話就直接去存
stco[ram[0]] = [i+1]
stcoset.add(ram[0])
else:stco[ram[0]].append(i+1)
if ram[1] not in encoset:
enco[ram[1]] = [i+1]#因為算從右邊過來的總和時排列順序沒調成原本的d的順序 所以就跟從左邊開始的順序一樣底下好計算
encoset.add(ram[1])
else:enco[ram[1]].append(i+1)
sttotal.append(sttotal[i] + d[i+1])
entotal.append(entotal[i] + d[a-i-2])
def loop():
global maxs
matchs = []
for i in stcoset:
if i*-1 in encoset:matchs.append(i)#這組數字可以用
for i in matchs:
stkey = sorted(stco[i])
enkey = sorted(enco[i*-1])
#print(stkey,enkey,i)
for o in stkey:
nowb = len(enkey)-1#二分搜
nows = 0
#print(stkey,enkey,o,nows,nowb)
if sttotal[o] + entotal[enkey[nows]] > s:continue#若最小的都爆掉了就沒後續
elif sttotal[o] + entotal[enkey[nowb]] <= s:#若最大的都沒有爆掉了就沒後續
if (a -enkey[nowb]) >o:#目前位置在o的右邊
if sttotal[o] + entotal[enkey[nowb]]>maxs:maxs = sttotal[o] + entotal[enkey[nowb]]
continue
else:
try:
while (a -enkey[nowb]) <=o:nowb -= 1
except:continue#因為可能enkey只有一個所以加上TRY
while nowb>=nows:
ram = (nowb+nows)//2#目前在哪個位置
ram2 = sttotal[o] + entotal[enkey[ram]]
if ram2 == s:#剛好一樣大
maxs = s
return
if ram2 > s:nowb = ram - 1 # 總和超過,縮小上界
else:
maxs = max(maxs, ram2) # 更新最大值
nows = ram + 1 # 總和符合條件,提高下限
loop()
print(maxs)#目前問題:有時候會比正確答案大