Submission #138215

#TimeUsernameProblemLanguageResultExecution timeMemory
138215evpipisOlympiads (BOI19_olympiads)C++11
100 / 100
185 ms3160 KiB
#include <bits/stdc++.h>
using namespace std;

#define pb push_back

const int len = 503, inf = 1e9;
int mx[len], mine[len], who[len], score[10];
int par[len][len], sum[len][len], dp[len][10], best[len][10];
int n, k, c;

struct node{
    int opt;
    bitset<len> block, must;
    vector<int> extra; /// check what happens here

    node(bitset<len> bl, bitset<len> mu){
        block = bl;
        must = mu;
        /// assume that bl, mu are always valid sets

        // inits
        int rem = k-must.count();
        for (int j = 0; j < k; j++)
            score[j] = 0;
        for (int bit = 1; bit < (1<<k); bit++)
            mx[bit] = -inf, mine[bit] = 0;

        for (int i = 0; i < n; i++)
            if (must[i])
                for (int j = 0; j < k; j++)
                    score[j] = max(score[j], par[i][j]);
        for (int bit = 1; bit < (1<<k); bit++)
            for (int j = 0; j < k; j++)
                if (bit&(1<<j))
                    mine[bit] += score[j];

        for (int i = 0; i < n; i++){
            if (block[i]|must[i]) continue;

            for (int bit = 1; bit < (1<<k); bit++)
                if (sum[i][bit] > mx[bit])
                    mx[bit] = sum[i][bit], who[bit] = i;
        }

        // compute dp
        for (int bit = 1; bit < (1<<k); bit++){
            dp[bit][0] = -inf;
            for (int i = 1; i <= rem; i++){
                dp[bit][i] = -inf;
                for (int sub = bit; sub > 0; sub = (sub-1)&bit)
                    if (dp[bit-sub][i-1] != -inf && dp[bit-sub][i-1]+mx[sub] > dp[bit][i])
                        dp[bit][i] = dp[bit-sub][i-1]+mx[sub], best[bit][i] = sub;
            }
        }

        // find opt answer
        int cur = 0;
        for (int bit = 1; bit < (1<<k); bit++)
            if (dp[bit][rem]+mine[((1<<k)-1)-bit] > dp[cur][rem]+mine[((1<<k)-1)-cur])
                cur = bit;

        opt = dp[cur][rem]+mine[((1<<k)-1)-cur];

        // reconstruct useful team members
        while (cur > 0){
            extra.pb(who[best[cur][rem]]);
            cur -= best[cur][rem];
            rem--;
        }

        // add useless members
        sort(extra.begin(), extra.end());
        /*printf("mem now:");
        for (int j = 0; j < extra.size(); j++)
            printf(" %d", extra[j]);
        printf("\n");*/
        for (int i = n-1, j = (int)extra.size()-1; i >= 0 && rem; i--){
            while (j > 0 && extra[j] > i)
                j--;

            if ((j < 0 || i != extra[j]) && !block[i] && !must[i])
                extra.pb(i), rem--;
        }
    }

    bool operator<(const node &a) const{
        return (opt < a.opt);
    }

    void print(){
        printf("opt = %d\n", opt);

        printf("blocked:");
        for (int i = 0; i < n; i++)
            if (block[i])
                printf(" %d", i);
        printf("\n");

        printf("must:");
        for (int i = 0; i < n; i++)
            if (must[i])
                printf(" %d", i);
        printf("\n");

        printf("extra:");
        for (int i = 0; i < extra.size(); i++)
            printf(" %d", extra[i]);
        printf("\n");
    }
};

priority_queue<node> pq;

int main(){
    scanf("%d %d %d", &n, &k, &c);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < k; j++)
            scanf("%d", &par[i][j]);

    for (int i = 0; i < n; i++)
        for (int bit = 0; bit < (1<<k); bit++)
            for (int j = 0; j < k; j++)
                if (bit&(1<<j))
                    sum[i][bit] += par[i][j];

    int ans;
    bitset<len> block, must;
    pq.push(node(block, must));
    while (!pq.empty()){
        node u = pq.top();
        pq.pop();
        c--;

        //printf("c = %d, node u =\n", c);
        //u.print();

        if (c == 0){
            ans = u.opt;
            break;
        }

        block = u.block;
        must = u.must;
        for (int j = 0; j < u.extra.size(); j++){
            //printf("extra = %d\n", u.extra[j]);
            block[u.extra[j]] = 1;
            if (n-block.count() >= k){
                node v = node(block, must);
                //v.print();
                pq.push(v);
            }
            //printf("pushed\n");
            block[u.extra[j]] = 0;
            must[u.extra[j]] = 1;
        }
    }

    printf("%d\n", ans);
    return 0;
}

Compilation message (stderr)

olympiads.cpp: In member function 'void node::print()':
olympiads.cpp:106:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
         for (int i = 0; i < extra.size(); i++)
                         ~~^~~~~~~~~~~~~~
olympiads.cpp: In function 'int main()':
olympiads.cpp:144:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
         for (int j = 0; j < u.extra.size(); j++){
                         ~~^~~~~~~~~~~~~~~~
olympiads.cpp:147:33: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
             if (n-block.count() >= k){
                 ~~~~~~~~~~~~~~~~^~~~
olympiads.cpp:115:10: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
     scanf("%d %d %d", &n, &k, &c);
     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
olympiads.cpp:118:18: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
             scanf("%d", &par[i][j]);
             ~~~~~^~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...