Submission #74406

#TimeUsernameProblemLanguageResultExecution timeMemory
74406AdrienVannsonCultivation (JOI17_cultivation)C++14
60 / 100
2063 ms772 KiB
#pragma GCC optimize "O3,inline,unroll-loops,omit-frame-pointer"

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>
#include <set>
#include <vector>
#include <utility>

using namespace std;
using ll = long long;

const int oo = 2*1000*1000*1000 + 42;

const int NB_MAX_CELLULES_PLEINES = 300;

const int NB_MAX_INDEXS = 3*NB_MAX_CELLULES_PLEINES;
const int NB_MAX_EVENEMENTS = 2*NB_MAX_CELLULES_PLEINES;


int nbLignes, nbColonnes;

int nbCellulesPleines;
pair<int, int> cellulesPleines[NB_MAX_CELLULES_PLEINES];


struct Evenement
{
    bool estDebut;
    uint iColonne;
    uint iLigneDebut, iLigneFin;

    bool operator< (const Evenement &autre) const
    {
        if (iColonne != autre.iColonne) {
            return iColonne < autre.iColonne;
        }
        if (estDebut != autre.estDebut) {
            return estDebut;
        }
        if (iLigneDebut != autre.iLigneDebut) {
            return iLigneDebut < autre.iLigneDebut;
        }
        return iLigneFin < autre.iLigneFin;
    }
};

Evenement evenements[NB_MAX_EVENEMENTS];

bool getEstPossible (const uint nbBas, const uint nbDroite)
{
    int nbEvenements = 0;
    set<uint> ensembleLignesUtiles;

    for (int iCellulePleine=0; iCellulePleine<nbCellulesPleines; iCellulePleine++) {
        const uint iLigne = cellulesPleines[iCellulePleine].first;
        const uint iColonne = cellulesPleines[iCellulePleine].second;

        evenements[nbEvenements++] = Evenement{true, iColonne, iLigne, iLigne+nbBas+1};
        evenements[nbEvenements++] = Evenement{false, iColonne+nbDroite+1, iLigne, iLigne+nbBas+1};

        ensembleLignesUtiles.insert(iLigne);
        ensembleLignesUtiles.insert(iLigne+nbBas+1);

        if (iLigne > 0) {
            ensembleLignesUtiles.insert(iLigne-1);
        }
    }

    // Réindexation
    map<uint, int> reindexation;
    vector<pair<uint, int>> lignesUtiles; // {iLigne, index}

    int nouvelIndex = 0;
    for (uint iLigne : ensembleLignesUtiles) {
        reindexation[iLigne] = nouvelIndex;
        lignesUtiles.push_back(make_pair(iLigne, nouvelIndex));

        nouvelIndex++;
    }

    sort(evenements, evenements+nbEvenements);

    for (int iEvenement=0; iEvenement<nbEvenements; iEvenement++) {
        evenements[iEvenement].iLigneDebut = reindexation[evenements[iEvenement].iLigneDebut];
        evenements[iEvenement].iLigneFin = reindexation[evenements[iEvenement].iLigneFin];
    }

    int nbRecouvrements[NB_MAX_INDEXS];
    fill(nbRecouvrements, nbRecouvrements+NB_MAX_INDEXS, 0);

    int dernierPlein[NB_MAX_INDEXS];
    fill(dernierPlein, dernierPlein+NB_MAX_INDEXS, +oo);

    int nbDebutsVus = 0;

    for (int iEvenement=0; iEvenement<nbEvenements; iEvenement++) {
        const Evenement &evenement = evenements[iEvenement];

        const int iColonne = evenement.iColonne;

        // Vérification de la validité
        if (!evenement.estDebut && nbDebutsVus == nbCellulesPleines) {

            uint iLigneInvalide = -1;
            bool dernierValide = false;

            for (const pair<uint, int> &ligneUtile : lignesUtiles) {
                const uint iLigne = ligneUtile.first;
                const int index = ligneUtile.second;

                if (dernierValide && iLigne-iLigneInvalide-1 >= (uint)nbLignes) {
                    return true;
                }

                if (iColonne - dernierPlein[index] < nbColonnes) { // Invalide
                    iLigneInvalide = iLigne;
                    dernierValide = false;
                }
                else {
                    dernierValide = true;
                }

                if (iLigne - iLigneInvalide >= (uint)nbLignes) {
                    return true;
                }
            }
        }

        nbDebutsVus += evenement.estDebut;

        // Mise à jour
        for (uint iLigne=evenement.iLigneDebut; iLigne<evenement.iLigneFin; iLigne++) {
            nbRecouvrements[iLigne] += evenement.estDebut ? 1 : -1;

            if (nbRecouvrements[iLigne] == 0) {
                dernierPlein[iLigne] = +oo;
            }
            else if (dernierPlein[iLigne] == +oo) {
                dernierPlein[iLigne] = iColonne;
            }
        }

    }

    return false;
}


int main ()
{
    scanf("%d %d", &nbLignes, &nbColonnes);
    scanf("%d", &nbCellulesPleines);

    for (int iCellule=0; iCellule<nbCellulesPleines; iCellule++) {
        int iLigne, iColonne;
        scanf("%d %d", &iLigne, &iColonne);
        iLigne--, iColonne--;

        cellulesPleines[iCellule] = make_pair(iLigne, iColonne);
    }

    ll nbEtapesMin = +oo;
    ll nbBas = 0;
    ll nbDroite = 2*nbColonnes;

    //int nbIterations = 0;

    while (true) {

        ll nbBasAvant = nbBas;
        ll nbDroiteAvant = nbDroite;

        // Augmenter nbBas
        ll debut = nbBas - 1;
        ll fin = 2*nbLignes;

        while (fin-debut > 1) {
            const ll milieu = (debut + fin) / 2;

            if (getEstPossible(milieu, nbDroite-1)) {
                fin = milieu;
            }
            else {
                debut = milieu;
            }
        }
        nbBas = fin;

        // Diminuer nbDroite
        debut = -1;
        fin = nbDroite;

        while (fin-debut > 1) {
            const ll milieu = (debut + fin) / 2;

            if (getEstPossible(nbBas, milieu)) {
                fin = milieu;
            }
            else {
                debut = milieu;
            }
        }
        nbDroite = fin;


        nbEtapesMin = min(nbBas+nbDroite, nbEtapesMin);

        if ((nbBas == nbBasAvant && nbDroite == nbDroiteAvant) || nbDroite == 0) {
            break;
        }

        /*nbIterations++;
        cerr << nbIterations << endl;*/
    }

    printf("%lld\n", nbEtapesMin);

    return 0;
}

Compilation message (stderr)

cultivation.cpp: In function 'int main()':
cultivation.cpp:153:10: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
     scanf("%d %d", &nbLignes, &nbColonnes);
     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cultivation.cpp:154:10: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
     scanf("%d", &nbCellulesPleines);
     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
cultivation.cpp:158:14: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
         scanf("%d %d", &iLigne, &iColonne);
         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...