#44995: 想請教為何會卡在85%#python#補述


11216014@ymhs.tyc.edu.tw (030)

學校 : 國立楊梅高級中學
編號 : 240937
來源 : [220.137.88.97]
最後登入時間 :
2025-01-04 16:22:06
o079. 4. 最佳選擇 -- 2024年6月APCS | From: [220.137.85.13] | 發表日期 : 2025-01-01 14:18

解題想法:

開四個串列儲存從左到右以及又到左的的奇偶差和數字和

再開兩個字典儲存兩邊奇偶差的數字出現的位置(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)#目前問題:有時候會比正確答案大

 
#44998: Re: 想請教為何會卡在85%#python#補述


11216014@ymhs.tyc.edu.tw (030)

學校 : 國立楊梅高級中學
編號 : 240937
來源 : [220.137.88.97]
最後登入時間 :
2025-01-04 16:22:06
o079. 4. 最佳選擇 -- 2024年6月APCS | From: [220.137.85.13] | 發表日期 : 2025-01-01 14:58

 

我打完才發現打錯字 看的人不好意思W

 
#44999: Re: 想請教為何會卡在85%#python#補述


11216014@ymhs.tyc.edu.tw (030)

學校 : 國立楊梅高級中學
編號 : 240937
來源 : [220.137.88.97]
最後登入時間 :
2025-01-04 16:22:06
o079. 4. 最佳選擇 -- 2024年6月APCS | From: [220.137.85.13] | 發表日期 : 2025-01-01 15:04

 

二更:

我發現我一開始貼的些低級錯誤我<>打反

我改了下

現在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)#目前問題:有時候會比正確答案大

 
ZeroJudge Forum