P1 比例分割

思路

题目有提到兩個關鍵比較規則

  • S(l,k-1)/S(l,r)<a/a+b
  • S(l,k)/S(l,r)>=a/a+b

那我們可以推測:

  • 假如S(l,k-1)/S(l,r)>=a/a+b代表S(l,k-1)過大,l到k的範圍需要縮小
  • 假如S(l,k)/S(l,r)<a/a+b代表S(l,k-1)過小,l到k的範圍需要放大

演算法:

  • 因為一個一個試會時間爆掉,所以使用二分搜去夾出答案
  • 如果每次都去累加則會造成重複執行太多次一樣的動作,所以我們可以使用前啜和去解決這個問题
  • 如果找到可行的答案,則進行減枝,減少運行次數

AC code

from sys import stdin
n,m=map(int,stdin.readline().strip().split())
w=list(map(int,stdin.readline().strip().split()))
data=[list(map(int,stdin.readline().strip().split())) for _ in range(m)]
presum=[0]*(n+1)
for i in range(1,n+1):
    presum[i]=presum[i-1]+w[i-1]
#print(presum)
def find(l,r,a,b):
    def solve(l,r,a,b,k):
        global_num=a/(a+b)
        allsum=presum[r]-presum[l-1]
        x=presum[k-1]-presum[l-1]
        y=presum[k]-presum[l-1]
        if x/allsum>=global_num:
            return 0
        elif y/allsum<global_num:
            return 1
        else:
            return 2
    L=l
    R=r
    while L<R:
        mid=(L+R)//2
        current=solve(l,r,a,b,mid)
        if current==0:
            R=mid
        elif current==1:
            L=mid+1
        elif current==2:
            return mid
    return L
for l,r,a,b in data:
    print(find(l,r,a,b))

P2 觀光旅遊

思路(離散化+差分):

  • 先把出發時間排序,方便進行二分搜查詢
  • 對於m個表演進行離散化,創立一個長度為n的陣列diff,把diff[bisect_left(出發時間,起始時間)]+1,diff[bisect_right(出發時間,結束時間)] (要bisect_left(出發時間,起始時間)<=bisect_right(出發時間,結束時間)才成立)
  • 最後對diff做前啜和即可得出答案

AC code

from sys import stdin
import bisect
n,m=map(int,stdin.readline().strip().split())
t=list(map(int,stdin.readline().strip().split()))
data=[list(map(int,stdin.readline().strip().split())) for _ in range(m)]
t.sort()
diff=[0]*(n+1)
for i in data:
    L=bisect.bisect_left(t,i[0])
    R=bisect.bisect_right(t,i[1])-1
    if L<=R:
        diff[L]+=1
        diff[R+1]-=1
ans=0
current=0
for i in range(n):
    current+=diff[i]
    ans+=current
print(ans)