Practice Round APAC test 2017——Problem D. Sums of Sums

Problem

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, TT 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 ≤ Li ≤ Ri ≤ 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



二分查找阈值T,求出小于阈值T的字段和的个数,之后用前缀和求出和

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <math.h>
#include <algorithm>
using namespace std;

long long int a[200005];
long long int b[200005];

long long int tot,small;
int N;
long long int calc(long long int index)
{
    long long int low=small,high=tot,mid=(low+high)>>1,less=0,equal=0,ans=0,cnt;
    int i,j;
    
    while(low<=high)
    {
        mid=(low+high)>>1;
        less=0;
        equal=0;
        j=0;
        
        for(i=1;i<=N;i++)
        {
            while(j<i&&(a[i]-a[j])>mid)
                j++;
            
            
            if(i!=j)
            {
                if(a[i]-a[j]==mid)
                {
                    equal++;
                    less+=i-1-j;
                }
                else
                    less+=i-j;
            }
            
        }
        //cout<<mid<<" "<<less<<" "<<equal<<endl;
        if(less+equal<index)
            low=mid+1;
        else if(less>index)
            high=mid-1;
        else if(less+equal>=index)
            break;
    }
    
    ans+=(index-less)*mid;
    j=0;
    for(i=1;i<=N;i++)
    {
        while(j<i&&(a[i]-a[j])>mid)
            j++;
        
        if(j!=i)
        {
            if((a[i]-a[j])==mid)
            {
                ans+=(i-j-1)*a[i]-(b[i-1]-b[j]);
            }
            else
                ans+=(i-j)*a[i]-(b[i-1]-b[j-1]);
        }
        
    }
    return ans;
}

int main()
{
    int T,t,Q;
    long long int l,r;
    int i,j;
    
    freopen("/Users/fengguowen/Downloads/D-large-practice.in","r",stdin);
    freopen("/Users/fengguowen/Downloads/D-large-practice.out","w",stdout);
    cin>>T;
    
    for(t=1;t<=T;t++)
    {
        cin>>N>>Q;
        tot=0;
        small=200;
        for(i=1;i<=N;i++)
        {
            scanf("%lld",&a[i]);
            small=small>a[i]?a[i]:small;
            a[i]+=a[i-1];
            tot+=a[i];
            b[i]=tot;
        }
        cout<<"Case #"<<t<<":"<<endl;
        
        for(i=0;i<Q;i++)
        {
            cin>>l>>r;
            long long int ans= calc(r)-calc(l-1);
            cout<<ans<<endl;
        }

    }
    return 0;
}
/*
 1
 5 1
 5 4 3 2 1
 1 1
 
 1
 5 5
 5 4 3 2 1
 1 1
 1 10
 1 15
 3 8
 4 11
 */


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值