Cod sursa(job #1588545)

Utilizator gabrielinelusGabriel-Robert Inelus gabrielinelus Data 3 februarie 2016 10:55:02
Problema Statistici de ordine Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 5.76 kb
/**
(a)
    |SORT(A,p,r)
    |    m <- (p + r) / 2
    |    x <- MEDIAN(A,p,r)
    |    PARTITION(A,p,r,x)
    |    SORT(A,p,m-1)
    |    SORT(A,m+1,r)
    |[]
  Justification:
  The algorithm works as following: I put the median on the correct position and then, i do the same to the two halves.
  Thus, in the end I will get all possible medians in their correct position, and this means the array is sorted.
  Time complexity: T(n) = 2*T(n/2) + O(N) => O(NlogN)

(b)
    |SELECT(A,p,r,nth) /// returns the elemen which is on the n'th position in the array
    |   m <- (p + r) / 2
    |   x <- MEDIAN(A,p,r)
    |   IF m = nth THEN RETURN x
    |   IF m < nth THEN RETURN SELECT(A,m+1,r,nth)
    |   RETURN SELECT(A,p,m-1,nth)
    |[]

  Justification:
  The algorithm works as following: I search the interval [p,r] such that n'th element is it's middle. Thus, if n'th is current middle, i return it,
  otherwise, if nth is bigger than my middle, i search the middle in the right half, otherwise in the left half.
  Time complexity: T(n) = T(n/2) + O(N) => O(N)

(c)
    To use a single MEDIAN call, we hope that it is the middle of the [p,q] interval.
    If it is not, then we make it be the middle of the interval, by adding -INF at the beginning, or +INF at the ending of A.
    This is also linear time complexity and works as following:
    While nth > m, I add ininity at the end and update the new middle and the new q (length). This will shift the middle to the right until I reach the correct position
    While nth < m, I add infinity at the beginning and update the new ending, the new middle and the new nth position. As nth position grows by 1 each time I add -INF and the middle grows by 1 only after two steps, nth will reach the middle.
    Then, we just apply MEDIAN.
    Time complexity: the complexity of median. However, this has to be implemented using the partitioning and either randomized pivot, either buckets of 5, the complexity is O(N).

    For further details, check my C++ implementations.
*/
#include <bits/stdc++.h>

#define Nmax 3666013

using namespace std;

int N,K;
vector<int> A;

/// This API will partition vector V according to the boundaries [li,lf] and the value X

int Partition(vector<int> &V,int li,int lf,int X){
    for(int i = li ; i <= lf; ++i){
        if(V[i] == X)
            swap(V[i],V[lf - 1]);
        if(V[i] < X)
            swap(V[li++],V[i]);
    }
    swap(V[lf - 1],V[li]);
    return li;
}

/// This API will sort the elements using an O(N^2) sorting method
void Introsort(vector<int> &a,int li,int lf)
{
    for(int i = li + 1; i <= lf; ++i)
    {
        int aux = a[i],k = i;
        while(k > li && a[k-1] > aux)
        {
            a[k] = a[k-1];
            --k;
        }
        a[k] = aux;
    }
}

/// This API will return the element at pz'th position in a, in O(N) time.
int Med(vector<int> &a,int li,int lf,int pz)
{ /// O(N) time complexity, proved by T(N) = T(N/5) + T(7N/10) + bn
    if(lf - li + 1 <= 5){
        Introsort(a,li,lf);
        return a[li + pz];
    }

    vector<int> aux1,aux2;
    for(int i = li; i <= lf; ++i){
        aux1.push_back(a[i]);
        if((i-li) % 5 == 4){
            Introsort(aux1,0,4);
            aux2.push_back(aux1[2]);
            aux1.clear();
        }
    }
    if(aux1.size()){
        Introsort(aux1,0,aux1.size()-1);
        aux2.push_back( aux1[(aux1.size() - 1) / 2 ]);
    }

    int val = Med(aux2,0,aux2.size() - 1, (aux2.size() - 1)/2);
    int m = Partition(a,li,lf,val);
    if(m == pz)
        return a[m];
    if(m > pz)
        return Med(a,li,m + 1,pz);
    return Med(a,m + 1,lf,pz - m - 1);
}

///This API implements MEDIAN'
int Median(vector<int> &a,int li, int lf)
{
    int m = li + ((lf - li) >> 1);
    int k = Med(a,li,lf, m);
    return a[m];
}

///This API sorts the elements in O(NlogN) time
void NiceSort(vector<int> &a, int li,int lf)
{ /// T(n) = 2*T(n/2) + O(N) => O(NlogN)
    if(li >= lf)
        return;
    int m = li + ((lf - li) >> 1);
    int k = Med(a,li,lf, m);
    NiceSort(a,li, m - 1);
    NiceSort(a,m + 1, lf);
}

///This API selects the pz'th element in O(N) time
int Select(vector<int> &a, int li, int lf, int pz)
{ /// T(n) = T(n/2) + O(N) => O(N)
    int m = li + ((lf - li) >> 1);
    int k = Median(a,li,lf);
    if(m == pz)
        return a[m];
    if(m > pz)
        return Select(a,li,m - 1,pz);
    return Select(a,m+1,lf,pz);
}


/// This API will select the pz'th element in O(N) time, with just a single call of median
int PaddedSelect(vector<int> &a, int li, int lf,int pz)
{
    vector<int> New;
    int m = li + ((lf - li) >> 1);
    if(pz == m)
        New = a;
    else
        if(pz > m){
            New = a;
            while(pz > m)
            {
                New.push_back(999999999);
                ++lf;
                m = li + ((lf - li) >> 1);
            }
        }
        else
        {
            while(pz < m)
            {
                New.push_back(-999999999);
                ++pz;
                ++lf;
                m = li + ((lf - li) >> 1);
            }
            for(auto it : a)
                New.push_back(it);
        }
    /// Done the paddings
    Median(New,li,lf);
    return New[lf/2];
}

void Read()
{
    scanf("%d%d",&N,&K);
    A.resize(N);
    for(int i = 0; i < N; ++i)
        scanf("%d",&A[i]);
}

void Print()
{
    ///NiceSort(A,0,N-1);
    ///printf("%d\n",Median(A,0,N-1));
    printf("%d\n",Select(A,0,N-1,K-1));
    ///printf("%d\n",PaddedSelect(A,0,N-1,K-1));
    ///for(auto it : A)
       /// printf("%d ",it);
}

int main()
{
    freopen("sdo.in","r",stdin);
    freopen("sdo.out","w",stdout);
    Read();
    Print();

    return 0;
}