Reputation: 1525
Given an array a
of n
integers, count how many subsequences (non-consecutive as well) have sum % k = 0
:
1 <= k < 100
1 <= n <= 10^6
1 <= a[i] <= 1000
An O(n^2)
solution is easily possible, however a faster way O(n log n)
or O(n)
is needed.
Upvotes: 7
Views: 2345
Reputation: 23955
Traverse a
and count a[i] mod k
; there ought to be k
such counts.
Recurse and memoize over the distinct partitions of k, 2*k, 3*k...etc.
with parts less than or equal to k
, adding the products of the appropriate counts.
For example, if k
were 10
, some of the partitions would be 1+2+7
and 1+2+3+4
; but while memoizing, we would only need to calculate once how many pairs mod k
in the array produce (1 + 2)
.
For example, k = 5, a = {1,4,2,3,5,6}
:
counts of a[i] mod k: {1,2,1,1,1}
products of distinct partitions of k:
5 => 1
4,1 => 2
3,2 => 1
products of distinct partitions of 2 * k with parts <= k:
5,4,1 => 2
5,3,2 => 1
4,1,3,2 => 2
products of distinct partitions of 3 * k with parts <= k:
5,4,1,3,2 => 2
answer = 11
{1,4} {4,6} {2,3} {5}
{1,4,2,3} {1,4,5} {4,6,2,3} {4,6,5} {2,3,5}
{1,4,2,3,5} {4,6,2,3,5}
Upvotes: 0
Reputation: 65506
There's an O(n + k^2 lg n)
-time algorithm. Compute a histogram c(0), c(1), ..., c(k-1)
of the input array mod k
(i.e., there are c(r)
elements that are r
mod k
). Then compute
k-1
product (1 + x^r)^c(r) mod (1 - x^k)
r=0
as follows, where the constant term of the reduced polynomial is the answer.
Rather than evaluate each factor with a fast exponentiation method and then multiply, we turn things inside out. If all c(r)
are zero, then the answer is 1
. Otherwise, recursively evaluate
k-1
P = product (1 + x^r)^(floor(c(r)/2)) mod (1 - x^k).
r=0
and then compute
k-1
Q = product (1 + x^r)^(c(r) - 2 floor(c(r)/2)) mod (1 - x^k),
r=0
in time O(k^2)
for the latter computation by exploiting the sparsity of the factors. The result is P^2 Q mod (1 - x^k)
, computed in time O(k^2)
via naive convolution.
Upvotes: 0
Reputation: 43517
This is the subset sum problem.
A simple solution is this:
s = 0
dp[x] = how many subsequences we can build with sum x
dp[0] = 1, 0 elsewhere
for i = 1 to n:
s += a[i]
for j = s down to a[i]:
dp[j] = dp[j] + dp[j - a[i]]
Then you can simply return the sum of all dp[x]
such that x % k == 0
. This has a high complexity though: about O(n*S)
, where S
is the sum of all of your elements. The dp
array must also have size S
, which you probably can't even afford to declare for your constraints.
A better solution is to not iterate over sums larger than or equal to k
in the first place. To do this, we will use 2 dp
arrays:
dp1, dp2 = arrays of size k
dp1[0] = dp2[0] = 1, 0 elsewhere
for i = 1 to n:
mod_elem = a[i] % k
for j = 0 to k - 1:
dp2[j] = dp2[j] + dp1[(j - mod_elem + k) % k]
copy dp2 into dp1
return dp1[0]
Whose complexity is O(n*k)
, and is optimal for this problem.
Upvotes: 3