113262024-08-10 02:55:25kukkermanMaximális szorzat (50 pont)cpp17Accepted 50/5064ms1984 KiB
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdint>

void beolvas(std::istream &be, std::vector<int64_t> &v, int &k, int &b) {
    int n;
    be >> n >> k >> b;

    v.resize(n);
    for (auto &x : v) {
        be >> x;
    }
}

void feldolgoz(std::vector<int64_t> &a, int k, int b) {
    using std::cout;
    
    static const int64_t M = 1000000007;
    const auto n = static_cast<int>(a.size());

    sort(a.begin(), a.end());

    // Megkeressuk az elso nemnegativ szam poziciojat
    auto elso_nn = static_cast<int>(lower_bound(a.begin(), a.end(), 0) - a.begin());

    // Ha a feltetel tobb negativ szamot kovetel meg, mint ahany
    // eredetileg a sorozatban talalhato, akkor nincs megoldas.
    if (elso_nn < b) {
        cout << "-1\n";
        return;
    }

    // A 0-hoz legkozelebb eso negativ szamtol kezdve megprobalunk annyit
    // 0-ig novelni, hogy hogy pontosan az eloirt darabszamu maradjon.
    for (; elso_nn > b && k >= 0; elso_nn--) {
        // Levonjuk 'k'-bol az aktualis negativ szam 0-ig novelesenek koltseget.
        k += static_cast<int>(a[elso_nn - 1]);
        a[elso_nn - 1] = 0;
    }

    // Ha nincs elegendo valasztasunk ahhoz, hogy "eltuntessuk" a megfelelo darabszamu
    // negativ szamot, akkor nincs megoldas.
    if (k < 0) {
        cout << "-1\n";
        return;
    }

    // Ha az osszes megmaradt szam negativ, akkor nincs mas lehetoseg, mint ezek kozott
    // szetosztani 'k'-t, ami az ossz szorzat csokkenesevel fog jarni. Azonban ebben
    // az esetben is ugy jarunk a legjobban, ha a legkisebbol a legnagyobb fele haladva
    // osztjuk szet 'k'-t. Mivel a szetosztas az [elso_nn; n - 1] intervallumon tortenik,
    // ezert egyszeruen nullazzuk 'elso_nn'-t.
    if (elso_nn == n) {
        // Ellenorizzuk, hogy lehetseges-e ugy szetosztani 'k'-t, hogy mindegyik elem
        // negativ maradjon.
        int64_t s = k;
        for (int i = 0; i < n && s >= 0; i++) {
            s += a[i] + 1;
        }
        if (s > 0) {
            cout << "-1\n";
            return;
        }

        elso_nn = 0;
    }

    // Kiszamitjuk az elso nemnegativ szamtol kezdodoen egeszen a sorozat vegeig
    // az egyes elemek osszeget:
    // bal_osszeg[i] = az elso 'i' db. elem osszege az 'elso_nn' indextol kezdodoen
    std::vector<int64_t> bal_osszeg(n - elso_nn + 1, 0);
    for (int i = elso_nn; i < n; i++) {
        bal_osszeg[i - elso_nn + 1] = bal_osszeg[i - elso_nn] + a[i];
    }

    // Binaris kereses segitsegevel megkeressuk az elso olyan elem poziciojat,
    // amennyire mar eppen nem potolhatok ki a sorozat elemei az elso nemnegativ
    // elemtol kezdodoen. Pl.:
    // 
    // Legyen a = { -2, -1, 1, 3, 4 }, k = 3
    // 
    // Az elso nemnegativ elem pozicioja: elso_nn = 2. A sorozat kipotlasanak
    // a koltsege a 3. pozicioig 2 egyseg:  a = { -2, -1, 1 + 2, 3,     4 },
    // azonban a 4. pozicioig mar 4 egyseg: a = { -2, -1, 1 + 3, 3 + 1, 4 },
    // azaz a 4. az elso olyan pozicio, ameddig mar eppen nem potolhato ki 'k'
    // koltsegert.
    int eleje = elso_nn, vege = n;
    while (eleje < vege) {
        const auto kozep = eleje + (vege - eleje) / 2;
        // Az [elso_nn; kozep] indexu elemek 'a[kozep]'-re valo kipotlasanak koltsege.
        const auto koltseg = a[kozep] * (kozep - elso_nn + 1) - bal_osszeg[kozep - elso_nn + 1];

        if (k < koltseg) {
            vege = kozep;

        } else {
            eleje = kozep + 1;
        }
    }

    // Levonunk 'k'-bol annyit, amennyi elegendo az [elso_nn; vege - 1] sorszamu elemek
    // a[vege - 1]-re valo kipotlasahoz. Ekkor az osszes elem az [elso_nn; vege - 1]
    // tartomanyban egyenlo lesz a[vege - 1]-gyel.
    k -= static_cast<int>(a[vege - 1] * (vege - elso_nn) - bal_osszeg[vege - elso_nn]);

    // Kiszamitjuk, hogy a kipotlas utan maximum mennyire tudjuk az osszes elemet
    // az [elso_nn; vege - 1] tartomanyban megnovelni.
    const auto max_elem = a[vege - 1] + k / (vege - elso_nn);

    // Elkezdjuk kiszamitani a modositott vektor elemeinek a szorzatat, ugyelve
    // arra, hogy ne tortenjen tulcsordulas a szorzas soran.

    // Osszeszorozzuk a megmaradt negativ elemeket.
    int64_t s = 1;
    int i;
    for (i = 0; i < elso_nn; i++) {
        s = (s * -a[i]) % M;
    }

    // Osszesen 'k % (vege - elso_nn)' db. olyan elem lesz, amely a korabban kiszamitott
    // maximumon felul, tovabbi egy egyseggel novelhato.
    for (auto j = k % (vege - elso_nn); j > 0; j--) {
        s = s * (max_elem + M + 1) % M;
        i++;
    }

    // A maradek elemek erteke 'max_elem' lesz egeszen 'vege - 1'-ig. 
    for (; i < vege; i++) {
        s = s * (max_elem + M) % M;
    }

    // A vektor vegen pedig azok az elemek maradnak, amelyeket mar nem lehet
    // kipotolni, mert tulsagosan nagyok.
    for (; i < n; i++) {
        s = s * (a[i] + M) % M;
    }

    cout << s << '\n';
}

int main() {
    std::vector<int64_t> v;
    int k, b;
    beolvas(std::cin, v, k, b);

    feldolgoz(v, k, b);

    return 0;
}
SubtaskSumTestVerdictTimeMemory
base50/50
1Accepted0/03ms408 KiB
2Accepted0/03ms356 KiB
3Accepted0/03ms492 KiB
4Accepted0/03ms356 KiB
5Accepted0/06ms484 KiB
6Accepted2/23ms384 KiB
7Accepted2/23ms504 KiB
8Accepted2/23ms256 KiB
9Accepted2/23ms484 KiB
10Accepted2/27ms484 KiB
11Accepted2/254ms1872 KiB
12Accepted1/157ms1936 KiB
13Accepted1/13ms632 KiB
14Accepted1/17ms500 KiB
15Accepted1/123ms740 KiB
16Accepted1/124ms868 KiB
17Accepted1/123ms764 KiB
18Accepted1/113ms1144 KiB
19Accepted1/145ms1892 KiB
20Accepted1/134ms1912 KiB
21Accepted1/164ms1984 KiB
22Accepted1/127ms1148 KiB
23Accepted1/161ms1580 KiB
24Accepted1/159ms1748 KiB
25Accepted2/22ms356 KiB
26Accepted2/27ms484 KiB
27Accepted2/232ms1124 KiB
28Accepted1/132ms1052 KiB
29Accepted2/224ms868 KiB
30Accepted1/161ms1144 KiB
31Accepted1/143ms1252 KiB
32Accepted2/23ms256 KiB
33Accepted2/261ms1276 KiB
34Accepted1/161ms1272 KiB
35Accepted2/261ms1212 KiB
36Accepted2/261ms1392 KiB
37Accepted2/261ms1144 KiB
38Accepted2/261ms1144 KiB
39Accepted1/13ms360 KiB