计算可被K整除的子阵列

时间:2014-07-01 20:24:00

标签: c++ algorithm

给定n个正整数序列,我们需要计算连续的子序列,其总和可以被k整除。

约束:N最多10 ^ 6,每个元素最多10 ^ 9,K最多100

示例:令N = 5且K = 3且阵列为1 2 3 4 1

这里的答案是4

说明:存在4个子序列,其和可以被3整除,它们是

3
1 2
1 2 3
2 3 4

我的尝试:

long long int count=0;
for(int i=0;i<n;i++){
    long long int sum=0;
    for(int j=i;j<n;j++)
    {
        sum=sum+arr[j];
        if(sum%k==0)
        {
            count++;
        }
    }
}

但显然它的方法很糟糕。他们可以更好地解决这个问题吗?请帮忙。

完整问题:https://www.hackerrank.com/contests/w6/challenges/consecutive-subsequences

2 个答案:

答案 0 :(得分:21)

这是一个快速的O(n + k)解决方案:

1)让计算前缀和pref [i](对于0&lt; = i&lt; n)。

2)现在我们可以计算count [i] - 具有和i的模数k(0 <= i

3)答案是所有i的总和[i] *(count [i] - 1)/ 2。

4)最好以模k为前缀和计算,以避免溢出。

为什么会这样?让我们仔细看看可被k整除的子阵列。让我们说它从L位置开始并以R位置结束。当且仅当pref [L - 1] == pref [R](模k)时,它可以被k整除,因为它们的差值是零模k(通过可分性的定义)。因此,对于每个固定的模数,我们可以选择带有此前缀sum modulo k的任意两个前缀(并且确实有count [i] *(count [i] - 1)/ 2种方法)。

这是我的代码:

long long get_count(const vector<int>& vec, int k) {
  //Initialize count array.
  vector<int> cnt_mod(k, 0);
  cnt_mod[0] = 1;
  int pref_sum = 0;
  //Iterate over the input sequence.
  for (int elem : vec) {
    pref_sum += elem;
    pref_sum %= k;
    cnt_mod[pref_sum]++;
  }
  //Compute the answer.
  long long res = 0;
  for (int mod = 0; mod < k; mod++)
    res += (long long)cnt_mod[mod] * (cnt_mod[mod] - 1) / 2;
  return res;
}

答案 1 :(得分:0)

这必须使您的计算更容易:

//Now we will move all numbers to [0..K-1]
long long int count=0;
for(int i=0;i<n;i++){
    arr[i] = arr[i]%K;
}

//Now we will calculate cout of all shortest subsequences.
long long int sum=0; 
int first(0); 
std::vector<int> beg;
std::vector<int> end;
for(int i=0;i<n;i++){
    if (arr[i] == 0)
    {
        count++; 
        continue;
    }
    sum += arr[i];
    if (sum == K)
    {
        beg.push_back(first);
        end.push_back(i);
        count++;
    }
    else
    {
        while (sum > K)
        {
            sum -= arr[first];
            first++;     
        }
        if (sum == K)
        {
            beg.push_back(first);
            end.push_back(i);
            count++;
        }
    }        
}

//this way we found all short subsequences. And we need to calculate all subsequences that consist of some short subsequencies.
int party(0);
for (int i = 0; i < beg.size() - 1; ++i)
{
    if (end[i] == beg[i+1])
    {
        count += party + 1;
        party++;
    }
    else
    {
        party = 0;
    } 
}

因此,当max array size = 10 ^ 6且rest的最大大小= 99时,即使你需要在简单的int32中汇总所有数字,你也不会有溢出。

你将花费的时间将在O(n + n)

附近