LA 2678: Subsequence

LA 2678: Sub-sequence

Problem Statement


Analysis

    We are asked to find the length of the shortest sub-sequence such that the sum of all elements in it is at least S. In other words, given the array A_0 ~ A_N-1, find the smallest possible X such that there exists a i which satisfies ∑A_j ≥ S, where j = i ~ i + X - 1.
    For example, when A = [1, 2, 3, 4, 5], N = 5, and S = 11, the smallest possible X is 3 and the i is 2. This is sample test case 2.

Algorithm: O(N^3)

    The most naive method is to permute through all possible sub-sequence beginnings and ends.
There are N beginnings and N/2 ends on average, making just permuting through possible sub-sequences O(N^2). Multiplying by the cost of finding the sum of that sub-sequence, O(N), gives us a total O(N^3) algorithm. Clearly that will not work!

Algorithm: O(N^2)

    However, we can use a prefix sum to improve on the cost of finding the sum of that sub-sequence. During reading the input of an element the i-th element, say its value is V[i], let the prefix sum value of the i-th element be as follows:
S[i] = S[i-1] + V[i].
Sure enough, this shortens the O(N) cost of finding the sum to O(1), but we are left with O(N^2) - still to slow.

Algorithm: O(N log N)

    This algorithm also requires to use prefix sums. We can binary search for the smallest possible X. 
The search space satisfies the property for binary search:
The search space, 0 to N, must satisfy the property that if i is "doable" (doable being a binary predicate), i+1 must also be doable, and if i is not doable, i-1 must also be not doable. 
How? The sequence, A, is guaranteed to be positive. Therefore, for any sub-sequence, extending it will only increase its sum, and shortening it will only decrease its sum.

We can verify if this X is "doable" in O(N) - for each i from X to N - 1, find S[i] - S[i - X]. S is the array described above. If that value is greater than S, then X is doable, else, try a different i. If for no i is S[i] - S[i - X] greater than S, X is not doable. This O(N log N) approach definitely works - but can we do better?

Algorithm: O(N)

    How about only permuting the end, and find the last possible i such that the i-th element through the end of the sub-sequence has sum S? The larger i is, the better the solution. Furthermore, the best i for any end of the sub-sequence can only get bigger - never smaller. Therefore, this method is O(N) - just enough.

Code

Algorithm: O(N log N)

#include <cstring>
#include <iostream>
#define MAXN 100005
using namespace std;

int psum[MAXN], N, S;

bool doable(int X)
{
for(int i=X; i<=N; i++)
if(psum[i] - psum[i-X] >= S) return true;
return false;
}

int main()
{
ios_base::sync_with_stdio(false); cin.tie(nullptr);
while(cin >> N >> S)
{
memset(psum, 0, sizeof psum);
for(int i=1; i<=N; i++)
{
int x;
cin >> x;
psum[i] = psum[i-1] + x;
}
if(psum[N] < S)
{
cout << 0 << endl;
continue;
}
int l = 1, r = N;
while(l < r)
{
int m = (l + r)/2;
if(doable(m)) r = m;
else l = m + 1;
}
cout << r << endl;
}
}

Algorithm: O(N)


#include <cstring>

#include <iostream>
#define MAXN 100005
using namespace std;

int psum[MAXN];

int main()
{
int N, S;
ios_base::sync_with_stdio(false);
while(cin >> N >> S)
{
memset(psum, 0, sizeof psum);
for(int i=1; i<=N; i++)
{
int x;
cin >> x;
psum[i] = psum[i-1] + x;
}
int ans=MAXN, i=1;
for(int e=1; e<=N; e++)
{
if(S > psum[e]) continue;
while(psum[i] <= psum[e] - S) i++;
ans = min(ans, e - i + 1);
}
cout << (ans == MAXN ? 0 : ans) << endl;
}
}

Comments

Popular posts from this blog

USACO Training "subset": Subset Sums

USACO 2018 Open: Talent Show

OpenJudge 1768: Kadane's Algorithm on 2D Arrays