Sums of Sums

Alice presented her friend Bob with an array of N positive integers, indexed from 1 to N. She challenged Bob with many queries of the form "what is the sum of the numbers between these two indexes?" But Bob was able to solve the problem too easily.

Alice took her array and found all N*(N+1)/2 non-empty subarrays of it. She found the sum of each subarray, and then sorted those values (in nondecreasing order) to create a new array, indexed from 1 to N*(N+1)/2. For example, for an initial array [2, 3, 2], Alice would generate the subarrays [2], [3], [2], [2, 3], [3, 2], and [2, 3, 2] (note that [2, 2], for example, is NOT a subarray). Then she'd take the sums -- 2, 3, 2, 5, 5, 7 -- and sort them to get a new array of [2, 2, 3, 5, 5, 7].

Alice has given the initial array to Bob, along with Q queries of the form "what is the sum of the numbers from index Li to Ri, inclusive, in the new array?" Now Bob's in trouble! Can you help him out?

Input

The first line of the input gives the number of test cases, T. T test cases follow. Each test case begins with one line with two space-separated integers N and Q, denoting the number of elements in the initial array and the number of Alice's queries. Then, there is one line with N space-separated integers, denoting the elements of Alice's initial array. Finally, there are Q more lines with two space-separated integers each: Li and Ri, the inclusive index bounds for the i-th query.

Output

For each test case, output one line with Case #x:, where x is the test case number (starting from 1). Then output Q more lines, each with one integer, representing the answers to the queries (in the order they were asked).

Limits

1 ≤ T ≤ 10.
1 ≤ Q ≤ 20.
1 ≤ each element of the initial array ≤ 100.
1 ≤ LiRi ≤ N*(N+1)/2.

Small dataset

1 ≤ N ≤ 103.

Large dataset

1 ≤ N ≤ 200000.

Sample


Input
 

Output
 
1
5 5
5 4 3 2 1
1 1
1 10
1 15
3 8
4 11

Case #1:
1
45
105
26
48

In sample case #1, Alice's new array would be: [1, 2, 3, 3, 4, 5, 5, 6, 7, 9, 9, 10, 12, 14, 15].

这是今年APAC2017 practice round 的D题,最后一题.需要求子数组和排序序列的L到R的和.暴力方法是枚举所有子数组,求和,排序,枚举所有子数组的复杂度为O(N*(N+1)), 对这个数组进行排序的复杂度为O(N^2)log(N^2), 空间复杂度为O(N^2).这种解法在数组大小为10万量级以上会爆内存,速度也会很慢,所以需要优化.所以要进行的是在不枚举所有子数组的和的情况下,进行L和R的查找,一个比较好的方法是对值二分.

即对子数组和的范围进行二分,开始 l = 0, r = sum(array). 通过不断二分找到一个数n, 使小于其值的子数组的数目等于或者刚刚大于L或者R.

对于一个特定的数值n如何查找小于或者等于该值子数组的数目呢,在prefix sum 数组上使用双指针进行遍历是一个非常好的解法. 开始left = 0(prefix sum第一个是dummy值),right=1.开始进行判断.最终可能正好找到这个值n, 和小于等于这个值的子数组的数目刚好等于L或者R, 不理想的情况是找不到这个值,也就是L中的只包含了和等于某个值n*的部分子数组.此时就得对二分结束的l和r做判断,找到一个刚好大于L或者的R的第一个值.

另外计算子数组和的求和也可以通过 prefix sum 的prefix sum来进行.但是一定要注意prefix sum本身就有dummy,要先除去这个dummy再计算prefix sum.最终这个算法的时间复杂度为O(nlogn).

__author__ = 'xiaqing'
def get_sum(psum, ss, k, N):
    #bit devide by value
    l = psum[0]
    r = psum[-1]
    while l+1 < r:
        mid = (l+r)/2
        count = 0
        lp = 0
        rp = 1
        for lp in xrange(N):
            while rp <= N and psum[rp] - psum[lp] <= mid :
                rp += 1
            count += rp - lp -1
        if count < k:
            l = mid
        elif count > k:
            r = mid
        else:
            break
    if l + 1 < r:
        l = mid #use l as the finally calculate element
    else:
        lp = 0
        rp = 1
        count = 0
        for lp in xrange(N):
            while rp <= N and psum[rp] - psum[lp] <= l :
                rp += 1
            count += rp - lp -1
        if count < k: # make sure that l is the first value that make the count larger or equal to k, l is not qualified, count r's number
            l = r
            lp = 0
            rp = 1
            count = 0
            for lp in xrange(N):
                while rp <= N and psum[rp] - psum[lp] <= l :
                    rp += 1
                count += rp - lp -1
# how to calculate the last output
    lp = 0
    rp = 1
    ans = 0
    for lp in xrange(N):
        while rp <= N and psum[rp] - psum[lp] <= l :
            rp += 1
        ans += ss[rp-1] - ss[lp] - (rp-lp-1)*psum[lp]
    ans -= (count - k)*l

    return ans

input = open('./D-large-practice.in','r')
output = open('./D-large-practice.out','w')
T = int(input.readline().strip())
for n in xrange(T):
    output.writelines('Case #%s:\n'%(n+1))
    N,Q = map(int, input.readline().strip().split())
    array = map(int, input.readline().strip().split())
    psum = [0]
    ss = [0]
    for i in array:
        psum.append(psum[-1]+i)
    for i in psum[1:]:  #除去dummy
        ss.append(ss[-1]+i)
    for j in xrange(Q):
        l, r = map(int, input.readline().strip().split())
        output.writelines('%s\n'%(get_sum(psum, ss, r, N)-get_sum(psum, ss, l-1, N)))

 

转载于:https://www.cnblogs.com/sherylwang/p/5620780.html

你可能感兴趣的:(Sums of Sums)