Sums of Sums

Practice Round APAC test 2017


   Submissions
Lazy Spelling Bee
5pt
Correct
698/1266 users correct (55%)
8pt
Correct
496/685 users correct (72%)
Robot Rock Band
6pt
Correct
480/622 users correct (77%)
14pt
Correct
142/407 users correct (35%)
Not So Random
11pt
Not attempted
204/310 users correct (66%)
20pt
Not attempted
109/158 users correct (69%)
Sums of Sums
8pt
Correct
230/395 users correct (58%)
28pt
Time expired
13/128 users correct (10%)
   Top Scores
Jayam 100
Seter 100
KillswitcherEngag... 100
onepunchman 100
Sumeet.Varma 100
gdragon007 100
libenchao 100
jpsagarm95 100
vaibhav227 100
liubiao2638 100
Practice Mode  Rank: 135 Score: 41

Problem D. Sums of Sums

This contest is open for practice. You can try every problem as many times as you like, though we won't keep track of which problems you solve. Read the Quick-Start Guide to get started.
Small input
8 points
Large input
28 points
Judge's response for last submission: Correct.

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

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].

题意是给一个数组,把它的N*(1+N)/2个子数组分别求和作为新数组的元素  ,新数组排序,对于Q个区间询问,分别给出排序后的数组的区间和。

我是用比较暴力的方法做的,事实证明6分钟可以跑出答案,谷歌给的8分钟内是可以提交的。- -由于我大意上了个厕所,比赛时候错过提交时间了。。。。


先把原数组前缀和求出来,一个二层循环求出新数组(这是最费时间的)。

大数据里面N可以达到20万,平方得到的新数组长度就有400亿。这种前缀和的思路根本开不了数组存。

但看数值发现初始数值每个最大100,20万个数加起来不超过2000万,也就是说新数组每个元素的最大值不超过2000万,2000万的数组还是开得了的,

sum数组统计下新元素每个数出现的次数。

现在就是怎么快速求出[l,r]区间的和了。

presum可以求出新数组前缀和。

那怎样确定l跟r的前缀和呢?

现在用num数组来存从1~i有多少个数,

然后在数组num里面对l进行二分搜索,

如果答案num[loc] 跟l相等,说明当前位置就是新数组的位置,减一代表前一个值。


lower_bound找到了就是相等,找不到就找大于这个值最近的一个数。

如果搜到的结果是大于l的,那就是当前数值的前l个是需要的,减一就是前缀和里面的减一。

r也是差不多的处理思想。

>_<哎不该乱上厕所的。。。。

排行榜前10的大神的做法还没看懂。。。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <set>
const int N = 20000010;
typedef long long ll;
using namespace std;
int mod = 1000000007;
ll num[N];
ll presum[N];
ll sum[20000010];
ll getans(ll &l, ll &r, int &n)
{
  int loc = lower_bound(num + 1, num + n + 1, l) - num;
  if (num[loc] == l)
  {
    if (sum[loc] == 1)
      l = presum[loc-1];
    else
      l = presum[loc-1] + (sum[loc]-1)*loc;
  }else
  {
    l = presum[loc-1] + (l - num[loc-1] - 1)*loc;
  }

 loc = lower_bound(num + 1, num + n + 1, r) - num;
  if (num[loc] == r)
  {
    r = presum[loc];
  }else
  {
    r = presum[loc-1] + (r - num[loc-1])*loc;
  }
  return r - l;
}
int main()
{
  
    freopen("in.txt","r",stdin);
  	freopen("out.txt", "w", stdout);
  	int T, cas = 1;
  	scanf("%d", &T);
  	while (T--)
  	{
  		int n, q;
  		scanf("%d%d", &n, &q);
      memset(sum, 0, sizeof(sum));
      for (int i = 1;i <= n; i++)
        scanf("%lld", num + i);

      presum[0] = 0;
      for (int i = 1;i <= n; i++)
        presum[i] = presum[i-1] + num[i];

      for (int i = 1; i <= n; i++)
      {
        for (int j = i; j <= n; j++)
        {
          sum[presum[j] - presum[i-1]]++;
        }
      }
      presum[0] = 0;
      for (int i = 20000000; i >= 0; i--)
        if (sum[i])
          {n = i;break;}
      for (int i = 1; i <= n; i++)
      {
        presum[i] = i*sum[i] + presum[i-1];
      }
      num[0] = 0;
      for (int i = 1; i <= n; i++)
        num[i] = num[i - 1] + sum[i];

      printf("Case #%d:\n", cas++); 
      for (int i = 0;i < q; i++)
      {
        ll l, r;
        scanf("%lld%lld", &l, &r);
        
        printf("%lld\n", getans(l, r, n));
      }  

  		
  	}
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值