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

### md5sums命令的使用方法 `md5sums` 是一个用于计算和验证文件 MD5 校验和的工具。它通过生成文件的 MD5 值来确保文件在传输或存储过程中未被篡改或损坏。以下是 `md5sums` 的语法、选项和示例。 #### 语法 ```bash md5sums [选项] [参数] ``` #### 常用选项 - `-b` 或 `--binary`: 以二进制模式读取文件。 - `-t` 或 `--text`: 将输入文件作为文本文件处理(默认行为)。 - `-c` 或 `--check`: 从指定文件中读取 MD5 校验和,并验证文件完整性。 - `--status`: 验证成功时不输出任何信息,仅通过返回值表示结果。 - `-w`: 当校验不正确时发出警告信息[^2]。 #### 示例 1. **生成单个文件的 MD5 校验值** ```bash md5sum myfile.txt ``` 输出示例: ``` f0ef7081e1539ac00ef5b761b4fb01b3 myfile.txt ``` 2. **生成 MD5 校验值并保存到文件** ```bash md5sum myfile.txt > myfile.txt.md5 ``` 此命令将生成的 MD5 校验值保存到 `myfile.txt.md5` 文件中[^2]。 3. **验证文件是否被修改** ```bash md5sum -c myfile.txt.md5 ``` 如果文件未被修改,输出如下: ``` myfile.txt: OK ``` 如果文件已被修改,输出如下: ``` myfile.txt: FAILED md5sum: WARNING: 1 computed checksum did NOT match ``` 4. **静默验证(无输出)** ```bash md5sum --status -c myfile.txt.md5 ``` 此命令不会输出任何信息,但会通过返回值表示验证结果。如果返回值为 `0`,表示校验成功;否则表示校验失败。 5. **计算字符串的 MD5 值** 在 Linux 中,可以通过以下方式计算字符串的 MD5 值: ```bash echo -n "hello world" | md5sum ``` 输出示例: ``` 5eb63bbbe01eeed093cb22bb8f5acdc3 - ``` 注意:`echo -n` 用于避免添加换行符[^3]。 #### 注意事项 - MD5 校验和通常以 32 位小写十六进制格式显示。 - 在下载文件时,建议使用 `md5sum` 验证文件完整性,以确保文件未被篡改或损坏[^4]。 ```python # Python 示例:计算文件的 MD5 值 import hashlib def calculate_md5(file_path): hash_md5 = hashlib.md5() with open(file_path, "rb") as f: for chunk in iter(lambda: f.read(4096), b""): hash_md5.update(chunk) return hash_md5.hexdigest() file_path = "example.txt" print(f"MD5 of {file_path}: {calculate_md5(file_path)}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值