Submission details
Task:Yhdistelmät
Sender:Metabolix
Submission time:2025-11-29 23:00:02 +0200
Language:C++ (C++20)
Status:READY
Result:62
Feedback
groupverdictscore
#1ACCEPTED16
#2ACCEPTED17
#3ACCEPTED29
#40
Test results
testverdicttimegroup
#1ACCEPTED0.00 s1, 2, 3, 4details
#2ACCEPTED0.15 s1, 3, 4details
#3ACCEPTED0.13 s1, 4details
#4ACCEPTED0.14 s1, 4details
#5ACCEPTED0.14 s1, 4details
#6ACCEPTED0.14 s1, 4details
#7ACCEPTED0.14 s1, 4details
#8ACCEPTED0.14 s1, 4details
#9ACCEPTED0.15 s1, 4details
#10ACCEPTED0.15 s1, 4details
#11ACCEPTED0.00 s2, 3, 4details
#12ACCEPTED0.01 s3, 4details
#13ACCEPTED0.01 s4details
#14ACCEPTED0.44 s4details
#15--4details
#16--4details
#17--4details
#18ACCEPTED0.00 s1, 2, 3, 4details
#19ACCEPTED0.00 s1, 2, 3, 4details
#20ACCEPTED0.01 s4details
#21ACCEPTED0.00 s4details

Compiler report

input/code.cpp: In function 'void ratkaise(std::vector<int>, std::unordered_map<std::bitset<128>, int>, bool)':
input/code.cpp:142:10: warning: variable 'purkkaratkaisu_joka_toimii_d2' set but not used [-Wunused-but-set-variable]
  142 |     auto purkkaratkaisu_joka_toimii_d2 = [&]() {
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
input/code.cpp:172:10: warning: variable 'purkkaratkaisu' set but not used [-Wunused-but-set-variable]
  172 |     auto purkkaratkaisu = [&]() {
      |          ^~~~~~~~~~~~~~

Code

#include <bits/stdc++.h>
using namespace std;

typedef bitset<128> bits_t;

void lue_syote(vector<int>& hinnat, unordered_map<bits_t, int>& palkkiot) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;
    hinnat.resize(n);
    for (int i = 0; i < n; ++i) {
        cin >> hinnat[i];
    }

    palkkiot.clear();
    for (int i = 0; i < m; ++i) {
        bits_t yhdistelmä;
        int k, x;
        cin >> k >> x;
        for (int j = 0; j < k; ++j) {
            int indeksi;
            cin >> indeksi;
            indeksi -= 1;
            yhdistelmä.set(indeksi);
        }
        palkkiot[yhdistelmä] += x;
    }
}

void luo_syote(vector<int>& hinnat, unordered_map<bits_t, int>& palkkiot, int seed) {
    srand(seed);
    int n = 20, m = n + rand() % 20 + 1;
    hinnat.resize(n);
    for (int i = 0; i < n; ++i) {
        hinnat[i] = rand() % 1000 + 1;
    }

    palkkiot.clear();
    for (int i = 0; i < m; ++i) {
        bits_t yhdistelmä;
        int k = rand() % n + 1;
        for (int j = 0; j < k; ++j) {
            int indeksi = rand() % n;
            yhdistelmä.set(indeksi);
        }
        int x = rand() % 1000 + 1;
        palkkiot[yhdistelmä] += x;
    }
}

void ratkaise(vector<int> hinnat, unordered_map<bits_t, int> palkkiot, bool testi) {
    int n = hinnat.size();

    for (int i = 0; i < n; ++i) {
        int paras_arvo = -hinnat[i];
        for (const auto& [yhdistelmä, palkkio] : palkkiot) {
            if (yhdistelmä.test(i)) {
                paras_arvo += palkkio;
            }
        }
        if (paras_arvo <= 0) {
            unordered_set<bits_t> poistettavat;
            for (const auto& [yhdistelmä, palkkio] : palkkiot) {
                if (yhdistelmä.test(i)) {
                    poistettavat.insert(yhdistelmä);
                }
            }
            for (const auto& yhdistelmä : poistettavat) {
                palkkiot.erase(yhdistelmä);
            }
        }
    }

    int d = 0;
    for (const auto& [yhdistelmä, _] : palkkiot) {
        d = max(d, (int) yhdistelmä.count());
    }

    auto laske_arvo = [&](bits_t yhdistelmä) {
        int arvo = 0;
        for (int i = 0; i < n; ++i) {
            if (yhdistelmä.test(i)) {
                arvo -= hinnat[i];
            }
        }
        for (const auto& [palkkio_yhdistelmä, palkkio] : palkkiot) {
            if ((yhdistelmä & palkkio_yhdistelmä) == palkkio_yhdistelmä) {
                arvo += palkkio;
            }
        }
        return arvo;
    };

    auto ilmoita_tulos = [&](bits_t yhdistelmä) {
        cout << laske_arvo(yhdistelmä) << "\n";
        cout << yhdistelmä.count() << "\n";
        for (int i = 0; i < n; ++i) {
            if (yhdistelmä.test(i)) {
                cout << (i + 1) << " ";
            }
        }
        cout << endl;
    };

    bits_t selvästi_kannattavat;
    int selvästi_kannattavat_arvo = 0;
    for (int i = 0; i < n; ++i) {
        bool muutos = false;
        for (const auto& [yhdistelmä, palkkio] : palkkiot) {
            bits_t uusi = selvästi_kannattavat | yhdistelmä;
            if (uusi == selvästi_kannattavat) {
                continue;
            }
            int uusi_arvo = laske_arvo(uusi);
            if (uusi_arvo >= selvästi_kannattavat_arvo) {
                muutos = true;
                selvästi_kannattavat = uusi;
                selvästi_kannattavat_arvo = uusi_arvo;
            }
        }
        if (!muutos) {
            break;
        }
    }

    auto pieni_tapaus = [&]() {
        bits_t paras_yhdistelmä = 0;
        int paras_arvo = 0;
        for (uint32_t yhdistelmä = 0; yhdistelmä < (uint32_t(1) << n); ++yhdistelmä) {
            bits_t bs_yhdistelmä(yhdistelmä);
            int arvo = laske_arvo(bs_yhdistelmä);
            if (arvo > paras_arvo) {
                paras_yhdistelmä = bs_yhdistelmä;
                paras_arvo = arvo;
            }
        }
        return paras_yhdistelmä;
    };

    auto purkkaratkaisu_joka_toimii_d2 = [&]() {
        bits_t paras_yhdistelmä = selvästi_kannattavat;
        int paras_arvo = laske_arvo(paras_yhdistelmä);
        for (const auto& [yhdistelmä, palkkio] : palkkiot) {
            bits_t uusi = selvästi_kannattavat | yhdistelmä;
            int uusi_arvo = laske_arvo(uusi);
            unordered_set<bits_t> kokeilematta;
            for (const auto& [toinen_yhdistelmä, _] : palkkiot) {
                if ((uusi | toinen_yhdistelmä) != uusi) {
                    kokeilematta.insert(toinen_yhdistelmä);
                }
            }
            while (kokeilematta.size()) {
                bits_t toinen_yhdistelmä = *kokeilematta.begin();
                kokeilematta.erase(kokeilematta.begin());
                bits_t uusi2 = uusi | toinen_yhdistelmä;
                int uusi2_arvo = laske_arvo(uusi2);
                if (uusi2_arvo > uusi_arvo) {
                    uusi = uusi2;
                    uusi_arvo = uusi2_arvo;
                }
            }
            if (uusi_arvo > paras_arvo) {
                paras_yhdistelmä = uusi;
                paras_arvo = uusi_arvo;
            }
        }
        return paras_yhdistelmä;
    };

    auto purkkaratkaisu = [&]() {
        bits_t paras_yhdistelmä = selvästi_kannattavat;
        int paras_arvo = laske_arvo(paras_yhdistelmä);
        auto paranna = [&](bits_t uusi) {
            int uusi_arvo = laske_arvo(uusi);
            if (uusi_arvo > paras_arvo) {
                paras_yhdistelmä = uusi;
                paras_arvo = uusi_arvo;
            }
            return uusi_arvo;
        };
        auto rekursio = [&](bits_t nykyinen, int nykyinen_arvo, auto it, auto& rekurssio_ref, int taso) -> void {
            if (taso >= 3) {
                return;
            }
            for (auto it1 = it; it1 != palkkiot.end(); ++it1) {
                for (auto it2 = it; it2 != palkkiot.end(); ++it2) {
                    bits_t uusi = nykyinen | it2->first;
                    if (uusi == nykyinen) {
                        continue;
                    }
                    int uusi_arvo = paranna(uusi);
                    if (uusi_arvo >= nykyinen_arvo) {
                        nykyinen = uusi;
                        nykyinen_arvo = uusi_arvo;
                    }
                }
            }
            for (auto it2 = it; it2 != palkkiot.end(); ++it2) {
                bits_t uusi = nykyinen | it2->first;
                if (uusi == nykyinen) {
                    continue;
                }
                int uusi_arvo = paranna(uusi);
                if (uusi_arvo >= nykyinen_arvo) {
                    nykyinen = uusi;
                    nykyinen_arvo = uusi_arvo;
                }
                rekurssio_ref(uusi, uusi_arvo, next(it2), rekurssio_ref, taso + 1);
            }
        };
        rekursio(selvästi_kannattavat, selvästi_kannattavat_arvo, palkkiot.begin(), rekursio, 0);
        return paras_yhdistelmä;
    };

    auto heuristiikka = [&]() {
        map<int, bits_t> tilanteet;
        tilanteet[selvästi_kannattavat_arvo] = selvästi_kannattavat;
        for (const auto& [yhdistelmä, _] : palkkiot) {
            map<int, bits_t> uudet_tilanteet;
            for (auto [_, edellinen]: tilanteet) {
                bits_t uusi = edellinen | yhdistelmä;
                if (uusi != edellinen) {
                    int uusi_arvo = laske_arvo(uusi);
                    tilanteet[uusi_arvo] = uusi;
                    if (uusi_arvo >= selvästi_kannattavat_arvo) {
                        selvästi_kannattavat = uusi;
                        selvästi_kannattavat_arvo = uusi_arvo;
                    }
                }
            }
            while (tilanteet.size() > 16000) {
                tilanteet.erase(tilanteet.begin());
            }
        }
        return selvästi_kannattavat;
    };

    bits_t paras_yhdistelmä;
    bits_t oikea_yhdistelmä;
    if (testi) {
        oikea_yhdistelmä = pieni_tapaus();
        paras_yhdistelmä = heuristiikka();
        if (paras_yhdistelmä != oikea_yhdistelmä) {
            ilmoita_tulos(oikea_yhdistelmä);
            cout << "----\n";
            ilmoita_tulos(paras_yhdistelmä);
            throw runtime_error("VIRHE");
        }
        return;
    } else if (d == 1) {
        paras_yhdistelmä = selvästi_kannattavat;
    } else if (n <= 20) {
        paras_yhdistelmä = pieni_tapaus();
    } else {
        paras_yhdistelmä = heuristiikka();
    }
    ilmoita_tulos(paras_yhdistelmä);
}

int main(int argc, char** argv) {
    vector<int> hinnat;
    unordered_map<bits_t, int> palkkiot;
    if (argc == 2 && string(argv[1]) == "kotitesti") {
        try {
            lue_syote(hinnat, palkkiot);
            ratkaise(hinnat, palkkiot, true);
            for (int seed = 1; seed <= 1000; ++seed) {
                cerr << "Testi " << seed << "\n";
                luo_syote(hinnat, palkkiot, seed);
                ratkaise(hinnat, palkkiot, true);
            }
        } catch (runtime_error& e) {
            cerr << e.what() << "\n";
        }
    } else {
        lue_syote(hinnat, palkkiot);
        ratkaise(hinnat, palkkiot, false);
    }
}

Test details

Test 1

Group: 1, 2, 3, 4

Verdict: ACCEPTED

input
20 20
80 69 91 47 74 75 94 22 100 43...

correct output
446
11
2 3 5 8 10 13 14 15 17 19 20 

user output
446
11
2 3 5 8 10 13 14 15 17 19 20 

Test 2

Group: 1, 3, 4

Verdict: ACCEPTED

input
20 20
5 42 7 18 55 64 64 83 73 44 22...

correct output
425
11
1 2 3 4 7 10 13 16 18 19 20 

user output
425
11
1 2 3 4 7 10 13 16 18 19 20 

Test 3

Group: 1, 4

Verdict: ACCEPTED

input
20 20
30 98 55 69 40 3 95 12 64 56 3...

correct output
284
8
1 3 8 10 15 16 18 19 

user output
284
7
1 3 8 10 15 18 19 

Test 4

Group: 1, 4

Verdict: ACCEPTED

input
20 20
11 44 58 8 16 52 20 43 24 31 4...

correct output
348
10
2 4 5 7 11 13 15 16 18 20 

user output
348
10
2 4 5 7 11 13 15 16 18 20 

Test 5

Group: 1, 4

Verdict: ACCEPTED

input
20 20
53 44 5 37 88 36 81 47 85 97 3...

correct output
119
13
1 2 4 8 10 11 13 14 16 17 18 1...

user output
119
13
1 2 4 8 10 11 13 14 16 17 18 1...

Test 6

Group: 1, 4

Verdict: ACCEPTED

input
20 20
20 27 75 94 48 62 37 55 49 67 ...

correct output
478
11
1 2 5 7 10 12 13 15 16 17 18 

user output
478
11
1 2 5 7 10 12 13 15 16 17 18 

Test 7

Group: 1, 4

Verdict: ACCEPTED

input
20 20
32 28 67 72 32 76 53 30 47 67 ...

correct output
215
10
2 4 5 7 8 9 11 13 16 20 

user output
215
10
2 4 5 7 8 9 11 13 16 20 

Test 8

Group: 1, 4

Verdict: ACCEPTED

input
20 20
39 72 74 79 49 45 73 44 37 4 7...

correct output
185
13
1 3 5 6 7 8 10 13 14 16 17 18 ...

user output
185
11
1 3 7 8 10 13 14 16 17 18 20 

Test 9

Group: 1, 4

Verdict: ACCEPTED

input
20 20
41 56 65 78 2 13 17 42 83 76 9...

correct output
95
11
2 4 5 6 7 8 13 14 17 18 19 

user output
95
11
2 4 5 6 7 8 13 14 17 18 19 

Test 10

Group: 1, 4

Verdict: ACCEPTED

input
20 20
43 1 20 61 25 46 2 18 36 1 85 ...

correct output
111
8
1 2 3 7 8 10 16 19 

user output
111
8
1 2 3 7 8 10 16 19 

Test 11

Group: 2, 3, 4

Verdict: ACCEPTED

input
100 100
992248 852673 366775 737068 56...

correct output
30642743
46
3 5 6 9 11 12 15 16 17 18 21 2...

user output
30642743
46
3 5 6 9 11 12 15 16 17 18 21 2...

Test 12

Group: 3, 4

Verdict: ACCEPTED

input
100 100
153790 361741 45017 47184 9422...

correct output
16529629
39
2 3 4 5 10 12 14 17 24 25 26 3...

user output
16529629
39
2 3 4 5 10 12 14 17 24 25 26 3...

Test 13

Group: 4

Verdict: ACCEPTED

input
100 100
186797 446409 957173 150683 17...

correct output
14928280
62
1 2 8 9 10 11 12 14 15 16 17 2...

user output
14928280
62
1 2 8 9 10 11 12 14 15 16 17 2...

Test 14

Group: 4

Verdict: ACCEPTED

input
100 100
343213 582494 707357 104682 66...

correct output
11308944
72
1 3 4 5 6 7 8 9 10 11 12 13 14...

user output
11308944
72
1 3 4 5 6 7 8 9 10 11 12 13 14...

Test 15

Group: 4

Verdict:

input
100 100
922546 12088 805566 351521 644...

correct output
3311952
10
14 17 26 29 64 65 70 76 83 95 

user output
(empty)

Test 16

Group: 4

Verdict:

input
100 100
923042 35929 531316 587665 845...

correct output
519209
6
2 18 45 61 64 86 

user output
(empty)

Test 17

Group: 4

Verdict:

input
100 100
493725 218022 417464 531537 83...

correct output
1255541
11
16 19 24 29 30 50 60 62 67 74 ...

user output
(empty)

Test 18

Group: 1, 2, 3, 4

Verdict: ACCEPTED

input
1 1
2
1 1
1

correct output
0
0

user output
0
0

Test 19

Group: 1, 2, 3, 4

Verdict: ACCEPTED

input
1 1
1
1 2
1

correct output
1
1

user output
1
1

Test 20

Group: 4

Verdict: ACCEPTED

input
100 100
1000000 1000000 1000000 100000...

correct output
0
100
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

user output
0
100
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

Test 21

Group: 4

Verdict: ACCEPTED

input
100 100
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ...

correct output
99999900
100
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

user output
99999900
100
1 2 3 4 5 6 7 8 9 10 11 12 13 ...