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

Code

#include <climits>
#include <cstdint>
#include <iostream>
#include <tuple>
#include <vector>

using namespace std;

struct Maski {
    uint64_t a = 0;
    uint64_t b = 0;

    void lisaa(int x) {
        if(x < 64) {
            a |= uint64_t{1} << x;
        } else {
            b |= uint64_t{1} << (x - 64);
        }
    }
    void poista(int x) {
        if(x < 64) {
            a &= ~(uint64_t{1} << x);
        } else {
            b &= ~(uint64_t{1} << (x - 64));
        }
    }
    bool hae(int x) const {
        if(x < 64) {
            return (a & (uint64_t{1} << x)) != 0;
        } else {
            return (b & (uint64_t{1} << (x - 64))) != 0;
        }
    }

    int lkm() const {
        return __builtin_popcountll(a) + __builtin_popcountll(b);
    }

    bool operator==(const Maski& m) const {
        return a == m.a && b == m.b;
    }
    bool operator!=(const Maski& m) const {
        return a != m.a || b != m.b;
    }

    Maski operator&(const Maski& m) const {
        return {a & m.a, b & m.b};
    }
    Maski operator|(const Maski& m) const {
        return {a | m.a, b | m.b};
    }
    Maski operator~() const {
        return {~a, ~b};
    }
};

int n, m;
vector<int> esineenHinta;
vector<int> yhdistelmanPalkkio;
vector<Maski> yhdistelmanEsineet;
vector<Maski> esineenYhdistelmat;

pair<int, Maski> hae(Maski esineet, Maski yhdistelmat);

pair<int, Maski> hae2(Maski esineet, Maski yhdistelmat) {
    int suosituinEsineIdx = -1;
    int suosituinEsineYhdistelmaLkm = 0;
    for(int esineIdx = 0; esineIdx < n; ++esineIdx) {
        if(esineet.hae(esineIdx)) {
            int yhdistelmaLkm = (esineenYhdistelmat[esineIdx] & yhdistelmat).lkm();
            if(yhdistelmaLkm > suosituinEsineYhdistelmaLkm) {
                suosituinEsineIdx = esineIdx;
                suosituinEsineYhdistelmaLkm = yhdistelmaLkm;
            }
        }
    }

    if(suosituinEsineIdx == -1) {
        return {0, {}};
    }

    Maski loputEsineet = esineet;
    loputEsineet.poista(suosituinEsineIdx);

    int tulosTuotto = 0;
    Maski tulosEsineet;

    // Valitaan esine suosituinEsineIdx mukaan
    {
        int palkkiot = 0;
        Maski loputYhdistelmat = yhdistelmat;
        for(int yhdistelmaIdx = 0; yhdistelmaIdx < m; ++yhdistelmaIdx) {
            if(yhdistelmat.hae(yhdistelmaIdx) && (yhdistelmanEsineet[yhdistelmaIdx] & loputEsineet) == Maski()) {
                loputYhdistelmat.poista(yhdistelmaIdx);
                palkkiot += yhdistelmanPalkkio[yhdistelmaIdx];
            }
        }
        tie(tulosTuotto, tulosEsineet) = hae(loputEsineet, loputYhdistelmat);
        tulosTuotto += palkkiot - esineenHinta[suosituinEsineIdx];
        tulosEsineet.lisaa(suosituinEsineIdx);
    }

    // Jätetään esine suosituinEsineIdx valitsematta
    {
        Maski loputYhdistelmat = yhdistelmat;
        for(int yhdistelmaIdx = 0; yhdistelmaIdx < m; ++yhdistelmaIdx) {
            if(yhdistelmat.hae(yhdistelmaIdx) && yhdistelmanEsineet[yhdistelmaIdx].hae(suosituinEsineIdx)) {
                loputYhdistelmat.poista(yhdistelmaIdx);
            }
        }
        auto [tuotto2, esineet2] = hae(loputEsineet, loputYhdistelmat);
        if(tuotto2 > tulosTuotto) {
            tulosTuotto = tuotto2;
            tulosEsineet = esineet2;
        }
    }

    return {tulosTuotto, tulosEsineet};
}

struct UF {
    int vanhempi[100];

    UF() {
        for(int i = 0; i < 100; ++i) {
            vanhempi[i] = i;
        }
    }

    int hae(int x) {
        if(vanhempi[x] != x) {
            vanhempi[x] = hae(vanhempi[x]);
        }
        return vanhempi[x];
    }

    void yhdista(int x, int y) {
        x = hae(x);
        y = hae(y);
        vanhempi[x] = y;
    }
};

pair<int, Maski> hae(Maski esineet, Maski yhdistelmat) {
    UF uf;
    for(int yhdistelmaIdx = 0; yhdistelmaIdx < m; ++yhdistelmaIdx) {
        if(yhdistelmat.hae(yhdistelmaIdx)) {
            Maski jaljEsineet = esineet & yhdistelmanEsineet[yhdistelmaIdx];
            int edellinen = -1;
            for(int esineIdx = 0; esineIdx < n; ++esineIdx) {
                if(jaljEsineet.hae(esineIdx)) {
                    if(edellinen != -1) {
                        uf.yhdista(edellinen, esineIdx);
                    }
                    edellinen = esineIdx;
                }
            }
        }
    }

    int tulosTuotto = 0;
    Maski tulosEsineet;

    Maski jaljEsineet = esineet;
    for(int esineIdx = 0; esineIdx < n; ++esineIdx) {
        if(jaljEsineet.hae(esineIdx)) {
            jaljEsineet.poista(esineIdx);
            Maski komponentinEsineet;
            komponentinEsineet.lisaa(esineIdx); 
            for(int esineIdx2 = esineIdx + 1; esineIdx2 < n; ++esineIdx2) {
                if(jaljEsineet.hae(esineIdx2) && uf.hae(esineIdx) == uf.hae(esineIdx2)) {
                    jaljEsineet.poista(esineIdx2);
                    komponentinEsineet.lisaa(esineIdx2);
                }
            }
            Maski komponentinYhdistelmat;
            for(int yhdistelmaIdx = 0; yhdistelmaIdx < m; ++yhdistelmaIdx) {
                if(yhdistelmat.hae(yhdistelmaIdx) && (yhdistelmanEsineet[yhdistelmaIdx] & komponentinEsineet) != Maski()) {
                    komponentinYhdistelmat.lisaa(yhdistelmaIdx);
                }
            }
            auto [tuotto2, esineet2] = hae2(komponentinEsineet, komponentinYhdistelmat);
            tulosTuotto += tuotto2;
            tulosEsineet = (tulosEsineet | esineet2);
        }
    }

    return {tulosTuotto, tulosEsineet};
}

int main() {
    cin.sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> m;

    esineenHinta.resize(n);
    esineenYhdistelmat.resize(n);
    for(int& x : esineenHinta) {
        cin >> x;
    }

    yhdistelmanPalkkio.resize(m);
    yhdistelmanEsineet.resize(m);
    for(int yhdistelmaIdx = 0; yhdistelmaIdx < m; ++yhdistelmaIdx) {
        int k;
        cin >> k >> yhdistelmanPalkkio[yhdistelmaIdx];
        for(int j = 0; j < k; ++j) {
            int esineIdx;
            cin >> esineIdx;
            --esineIdx;
            yhdistelmanEsineet[yhdistelmaIdx].lisaa(esineIdx);
            esineenYhdistelmat[esineIdx].lisaa(yhdistelmaIdx);
        }
    }

    if(n <= 20 && m <= 20) {
        // epätoivoinen yritys servata testit 8)
        Maski kaikkiEsineet;
        for(int esineIdx = 0; esineIdx < n; ++esineIdx) {
            kaikkiEsineet.lisaa(esineIdx);
        }
        Maski kaikkiYhdistelmat;
        for(int yhdistelmaIdx = 0; yhdistelmaIdx < m; ++yhdistelmaIdx) {
            kaikkiYhdistelmat.lisaa(yhdistelmaIdx);
        }

        auto [tuotto, esineet] = hae(kaikkiEsineet, kaikkiYhdistelmat);

        cout << tuotto << "\n";

        int lkm = 0;
        for(int i = 0; i < n; ++i) {
            if(esineet.hae(i)) {
                ++lkm;
            }
        }
        cout << lkm << "\n";

        for(int i = 0; i < n; ++i) {
            if(esineet.hae(i)) {
                cout << i + 1 << " ";
            }
        }
        cout << "\n";

        return 0;
    }

    Maski esineet;
    Maski yhdistelmat;
    for(int i = 0; i < m; ++i) {
        esineet = esineet | yhdistelmanEsineet[i];
        yhdistelmat.lisaa(i);
    }

    int tulos = 0;
    for(int x : yhdistelmanPalkkio) {
        tulos += x;
    }
    for(int esineIdx = 0; esineIdx < n; ++esineIdx) {
        if(esineet.hae(esineIdx)) {
            tulos -= esineenHinta[esineIdx];
        }
    }

    while(true) {
        pair<int, int> parasMuutos = {INT_MIN, INT_MIN};
        Maski parasPoistettavatEsineet;
        Maski parasPoistettavatYhdistelmat;

        for(Maski ylajoukko : yhdistelmanEsineet) {
            int ylajoukkoLista[20];
            int ylajoukkoListaPituus = 0;
            for(int esineIdx = 0; esineIdx < n; ++esineIdx) {
                if(ylajoukko.hae(esineIdx)) {
                    ylajoukkoLista[ylajoukkoListaPituus++] = esineIdx;
                }
            }
            for(int valinta = 1; valinta < (1 << ylajoukkoListaPituus); ++valinta) {
                Maski poistettavatYhdistelmat;
                for(int i = 0; i < ylajoukkoListaPituus; ++i) {
                    if(valinta & (1 << i)) {
                        poistettavatYhdistelmat = poistettavatYhdistelmat | esineenYhdistelmat[ylajoukkoLista[i]];
                    }
                }

                Maski poistettavatYhdistelmatYhdiste;
                pair<int, int> muutos = {0, 0};
                for(int yhdistelmaIdx = 0; yhdistelmaIdx < m; ++yhdistelmaIdx) {
                    if(poistettavatYhdistelmat.hae(yhdistelmaIdx)) {
                        muutos.second -= yhdistelmanPalkkio[yhdistelmaIdx];
                        poistettavatYhdistelmatYhdiste = poistettavatYhdistelmatYhdiste | yhdistelmanEsineet[yhdistelmaIdx];
                    }
                }
                Maski poistettavatEsineet;
                for(int esineIdx2 = 0; esineIdx2 < n; ++esineIdx2) {
                    if(poistettavatYhdistelmatYhdiste.hae(esineIdx2) && (esineenYhdistelmat[esineIdx2] & poistettavatYhdistelmat) == esineenYhdistelmat[esineIdx2]) {
                        muutos.second += esineenHinta[esineIdx2];
                        poistettavatEsineet.lisaa(esineIdx2);
                    }
                }
                muutos.first = -poistettavatEsineet.lkm();
                if(muutos.second >= 0 && muutos > parasMuutos) {
                    parasMuutos = muutos;
                    parasPoistettavatEsineet = poistettavatEsineet;
                    parasPoistettavatYhdistelmat = poistettavatYhdistelmat;
                }
            }
        }

        if(parasMuutos == make_pair(INT_MIN, INT_MIN)) {
            break;
        }

        tulos += parasMuutos.second;
        esineet = esineet & ~parasPoistettavatEsineet;
        yhdistelmat = yhdistelmat & ~parasPoistettavatYhdistelmat;
        for(Maski& m : yhdistelmanEsineet) {
            m = m & ~parasPoistettavatEsineet;
        }
        for(Maski& m : esineenYhdistelmat) {
            m = m & ~parasPoistettavatYhdistelmat;
        }
        // cerr << "POIST ";
        for(int i = 0; i < n; ++i) {
            if(parasPoistettavatEsineet.hae(i)) {
                // cerr << i + 1 << " ";
                esineenYhdistelmat[i] = {};
            }
        }
        // cerr << ": " << parasMuutos << "\n";
        for(int i = 0; i < m; ++i) {
            if(parasPoistettavatYhdistelmat.hae(i)) {
                yhdistelmanEsineet[i] = {};
            }
        }
    }

    if(tulos < 0) {
        tulos = 0;
        esineet = {};
    }

    cout << tulos << "\n";
    cout << esineet.lkm() << "\n";
    for(int i = 0; i < n; ++i) {
        if(esineet.hae(i)) {
            cout << i + 1 << " ";
        }
    }
    cout << "\n";

    return 0;
}

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
8
1 3 8 10 15 16 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
13
1 3 5 6 7 8 10 13 14 16 17 18 ...

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
0
0

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
0
0

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:

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
(empty)

Test 21

Group: 4

Verdict:

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
(empty)