النتيجة#11806

النتيجة (شرح الحلول)

مؤلف المشكلة:

حسن صالح (MathModel)

أعده:

حسن صالح (MathModel)

تحرير:

حسن صالح (MathModel)

الحل البسيط هو التكرار عبر جميع الأجزاء الفرعية في المصفوفة وجمع الدرجات، مما يعطي حلاً \mathcal{O}(n^2). ومع ذلك، هذا بطيء جداً؛ نحتاج إلى القيام بذلك بشكل أسرع.

لتسريع الحساب، نحتاج إلى حساب لكل جزء فرعي ينتهي عند الفهرس ، كم عددها رائعة، وكم عددها مثالية، وكم عددها عادية.

دع يكون مجموع المصفوفة. يمكننا بسهولة تحديد ما إذا كان مجموع الجزء الفرعي أكبر من \frac{s}{2}، سيكون رائعاً؛ إذا كان أقل من \frac{s}{2}، سيكون عادياً، وإذا كان زوجياً ومجموع الجزء الفرعي يساوي \frac{s}{2}، سيكون مثالياً.

لذا، نحتاج إلى الحصول على مجموع سابق لكل فهرس p_i، وعدد الأجزاء التي هي أكبر من، تساوي، أو أقل من p_i - \frac{s}{2}. يمكن القيام بذلك بطرق عديدة؛ إحدى الطرق هي حساب جميع المجموعات السابقة ورسمها إلى الفهارس من 1-m، حيث هو عدد المجموعات السابقة المميزة. ثم يمكننا استخدام شجرة جزء أو شجرة فينووك مع البحث الثنائي لحل هذه المشكلة. سيجعل هذا تعقيد الوقت \mathcal{O}(n \log n)، وهو سريع بما يكفي لحل هذا باستخدام بايثون.

import bisect
class fenwick(object):
    def __init__(self, n):
        self.n = n
        self.cul = [0]*n
        self.maxd = len(bin(n))-3

    def update(self,index,diff):
        i = index
        while i<self.n:
            self.cul[i] += diff
            i += (i+1)&(-i-1)


    def getaccu(self,index):
        output = 0
        i = index
        while i>=0:
            output += self.cul[i]
            i -= (i+1)&(-i-1)
        return output

def solve():
    n = int(input())
    arr = list(map(int,input().split()))
    tot = sum(arr)
    nums = [0]
    for num in arr:
        nums.append(nums[-1]+num)
    nums = sorted(list(set(nums)))
    nums = [-float('inf')] + nums 
    mapping = {}
    already = {}
    already[0] = 1
    for i in range(len(nums)):
        mapping[nums[i]] = i
    fen = fenwick(len(nums)+1)
    fen.update(mapping[0],1) 
    count = 0
    accu = 0
    ans = 0
    for i,num in enumerate(arr):
        accu += num
        target = accu + (-tot) // 2
        loc = bisect.bisect(nums, target) - 1
        good = fen.getaccu(loc)
        ans += good * 2
        ans -= i + 1 - good
        if tot % 2 == 0 and target in already:
            ans += already[target]
        fen.update(mapping[accu],1)
        if accu not in already:  already[accu] = 0
        already[accu] += 1
    print(ans)

for _ in range(int(input())):
    solve()