1

Given a list of n non repeating integer numbers L:=(x1,...,xn) develop an algorithm that decides if there are xi1, xi2, xi3 in L such that i1 is lower than i2, i2 is lower than i_3, xi1 is lower than xi3 and xi3 is lower than xi2. Only a yes-no answer is required.

The statement also suggest to use the "divide & conquer" strategy.

My try was the following:

I read the vector left to right

  • If the list changes from increasing to decreasing, then it is clear that the last read number is lower than the maximum of the currently read list. So if it is greater than the minimum of the current list we can stop.
  • If the list changes from decreasing to increasing, then I look for the first number m in the list which is a local minimum and it is lower than the last read number c. And then I look for a local maximum appearing after m which is greater than c.
  • If the list keeps increasing we do the same as in the previous step.
  • If the list keeps decreasing do nothing.

So the complexity is nlogn. I think the strategy is good, but an online judge rejected it. I don't know if it is due to a silly bug or because the strategy is indeed wrong.

#include <iostream>
#include <algorithm>
#include <map>

using namespace std;

bool solveCase();
bool increasingCase(map<int, int> & mins, map<int, int> & maxs,
        pair<map<int, int>::iterator, bool> & lastMaxInserted,
        const int & current);
void ignoreStuff();

int main() {
    while (solveCase())
        ;
    return 0;
}

bool solveCase() {
    /*---Reading the number of children---*/
    int N;
    if (scanf("%d", &N) == EOF) {
        return false;
    }
    /*---Used variables---*/
    int globalMax;
    int globalMin;
    map<int, int> maxs;
    map<int, int> mins;
    int localMin;
    int localMinPos;
    bool increasing;
    pair<map<int, int>::iterator, bool> lastMaxInserted;
    int old;
    int current;
    /*-----Reading the first two children-----*/
    /*--Reading the first children--*/
    scanf("%d", &old);
    globalMax = old;
    globalMin = old;
    /*--Reading the second children--*/
    scanf("%d", &current);
    if (current > old) { /*The sequence starts increasing*/
        increasing = true;
        globalMax = current;
        localMin = old;
        localMinPos = 0;
    } else { /*The sequence starts decreasing*/
        increasing = false;
        globalMin = current;
        lastMaxInserted = maxs.insert(pair<int, int>(old, 0));
    }
    old = current;
    /*-----Reading the rest-----*/
    for (int i = 2; i < N; i++) {
        scanf("%d", &current); /*Reading a child*/
        if (!increasing) { /*--The sequence was decreasing--*/
            if (current < old) { /*The sequence keeps decreasing*/
                globalMin = min(current, globalMin);
            } else { /*The monotony changes*/
                localMin = old;
                localMinPos = i - 1;
                if (increasingCase(mins, maxs, lastMaxInserted, current)) {
                    printf("ELEGIR OTRA\n");
                    ignoreStuff(); /*Ignoring the rest*/
                    return true;
                }
                increasing = true;
            }
        } else { /*--The sequence was increasing--*/
            if (current > old) { /*The sequence keeps increasing*/
                globalMax = max(current, globalMax);
                if (increasingCase(mins, maxs, lastMaxInserted, current)) {
                    printf("ELEGIR OTRA\n");
                    ignoreStuff(); /*Ignoring the rest*/
                    return true;
                }
            } else { /*The monotony changes*/
                if (current > globalMin) { /*Check if we can end*/
                    printf("ELEGIR OTRA\n");
                    ignoreStuff(); /*Ignoring the rest*/
                    return true;
                } else {
                    globalMin = current;
                    /*Inserting the local minimum (saved somewhere)*/
                    map<int, int>::iterator minIter;
                    minIter = mins.lower_bound(localMin);
                    if (!mins.empty() && minIter != mins.begin()) {
                        /*The value is the minimum position of the local
                         * minimums lower than the current local minimum*/
                        minIter--;
                        mins.insert(pair<int, int>(localMin, minIter->second));
                    } else {
                        mins.insert(pair<int, int>(localMin, localMinPos));
                    }
                    /*Inserting the local maximum (old)*/
                    /*The value is the maximum position of the local
                     * maximums greater or equal than than the current
                     * local maximum (i.e. the position of the local
                     * maximum). The local maximums lower than the
                     * current maximum have incoherent values, but it
                     * doesn't matter...*/
                    lastMaxInserted = maxs.insert(pair<int, int>(old, i - 1));
                    increasing = false;
                }
            }
        }
        old = current;
    }
    printf("SIEMPRE PREMIO\n");
    return true;
}

bool increasingCase(map<int, int> & mins, map<int, int> & maxs,
        pair<map<int, int>::iterator, bool> & lastMaxInserted,
        const int & current) {
    if (!mins.empty()) {
        /*--Getting the position of the first local minimum lower than current--*/
        map<int, int>::iterator minIter;
        minIter = mins.lower_bound(current);
        if (minIter != mins.begin()) {
            minIter--;
        } else {
            return false;
        }
        int minPos = minIter->second;
        /*--Trying to get a good local maximum coming after the minimum--*/
        if (!maxs.empty()) {
            map<int, int>::iterator maxIter;
            maxIter = maxs.upper_bound(current);
            if (maxIter != maxs.end()) {
                if (maxIter->first < lastMaxInserted.first->first) {
                    if (minPos > lastMaxInserted.first->second) {
                        return false;
                    }
                } else {
                    if (minPos > maxIter->second) {
                        return false;
                    }
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
    return true;
}

void ignoreStuff() {
    char trash = getchar();
    while (trash != '\n') {
        trash = getchar();
    }
}

Any idea?

  • Why did it get rejected? Have you tried to test it yourself? – eesiraed Mar 17 '18 at 20:33
  • It just said "Wrong answer" (which means some test case is getting a wrong answer), yes I tried by myself, every case I have tested is correct – Álvaro G. Tenorio Mar 17 '18 at 20:34
  • Just wondering, why are you using C I/O in a C++ program? – eesiraed Mar 17 '18 at 20:40
  • It is way more fast than cin/cout, so programs written with scanf/printf get better scores in online judges and programming contests – Álvaro G. Tenorio Mar 17 '18 at 20:42
  • The only reason I know that C++ IO might be slower than C IO is unintentionally flushing the buffer with `std::endl`. My own testing with files shows that C++ IO is much faster than C IO, and it's only a tiny bit slower than C IO if you flush the buffer constantly. – eesiraed Mar 17 '18 at 21:14
  • My experiments say that in online judge problems, which usually requires from a lot IO operations, C IO is way faster (I'm talking about differences of seconds, 7s with cin/cout vs 0.3s with scanf/printf in a random problem I have just taken) but it may differ from one compiler to another. – Álvaro G. Tenorio Mar 17 '18 at 21:29
  • Back to the actual problem, I don't really know anything else you can do other than more testing and checking your logic. – eesiraed Mar 17 '18 at 21:34
  • As always with "judge rejected my code" questions, I am voting to close and dropping a hint: if you're clever, you can trick the judge into revealing the failing case. – Beta Mar 17 '18 at 21:35
  • I have realized that the sequence (6,4,7,2,3,1,5) produces a wrongs answer not due to a but nor a concept error, but because of the invariant of the maximums map is not preserved as it should be. For the example sequence the value of 6 in the map is 0 when it has to be 2. – Álvaro G. Tenorio Mar 18 '18 at 11:56
  • 1
    @FeiXiang There is also [this](https://stackoverflow.com/questions/9371238/why-is-reading-lines-from-stdin-much-slower-in-c-than-python). – user202729 Mar 19 '18 at 14:00
  • (which online judge are you using?) | In my experience, `cin/cout` with the tips above can pass all problems except the trivial ones which `O(n)` time complexity and low constant factors. So you don't need to worry too much about it. – user202729 Mar 19 '18 at 14:17

0 Answers0