Submission #727415

#TimeUsernameProblemLanguageResultExecution timeMemory
727415model_codeCouncil (JOI23_council)C++17
100 / 100
1373 ms104344 KiB
#include <array>
#include <bitset>
#include <iostream>
#include <vector>
using namespace std;

constexpr int N_MAX = 3e5, M_MAX = 20;
int popcnt(int x) { return bitset<32>(x).count(); }
int read() {
    int x;
    scanf("%d", &x);
    return x;
}
int A[N_MAX], agree[M_MAX], sum[1 << M_MAX][M_MAX], mn[1 << M_MAX][2];
int main() {
    const int N = read(), M = read();

    // 入力・各案に何票あるか数える
    for(int i = 0; i < N; i++) {
        for(int j = 0; j < M; j++) {
            const int x = read();
            A[i] |= x << j;
            agree[j] += x;
        }
    }

    // 可決に必要な票数
    const int need = N / 2;
    // need + 0 票の集合、need + 1 票の集合、need + 2 票以上の案の数
    int zero = 0, one = 0, two = 0;
    for(int i = 0; i < M; i++) {
        if(agree[i] == need) zero |= 1 << i;
        if(agree[i] == need + 1) one |= 1 << i;
        if(agree[i] >= need + 2) two++;
    }

    // sum[s][d] = 案の集合を s に絞ったとき、そのうち d 個に賛成している人の数
    for(int i = 0; i < N; i++) {
        const int a = A[i];
        sum[a][popcnt(a)]++;
    }
    // 高速ゼータ変換 (下位集合に累積和)
    for(int d = 0; d < M; d++) for(int s = 0; s < 1 << M; s++) if(s & 1 << d) {
                const int t = s ^ 1 << d, i = popcnt(s);
                sum[t][i - 1] += sum[s][i];
    }
    // 求めたいものを作る
    for(int d = 0; d < M; d++) for(int s = 0; s < 1 << M; s++) if(s & 1 << d) {
        const int t = s ^ 1 << d;
        for(int i = 0; i < M; i++) sum[s][i] += sum[t][i] - sum[s][i + 1];
    }
    // 各 s に対し d の first min, second min を求める
    for(int s = 0; s < 1 << M; s++) for(int d = M; d--; ) {
        if(sum[s][d] < 1) continue;
        if(sum[s][d] == 1) {
            mn[s][1] = mn[s][0];
            mn[s][0] = d;
        }
        else {
            mn[s][0] = d;
            mn[s][1] = d;
        }
    }
    // 各議員に対し答えを求める。
    for(int i = 0; i < N; i++) printf("%d\n", [&](int a) -> int {
        const int ZERO = (zero & ~a) | (one & a);
        const int rejected = mn[ZERO][mn[ZERO][0] == popcnt(a & ZERO)];
        return two + popcnt(one | ZERO) - rejected;
    }(A[i]));
}

Compilation message (stderr)

council.cpp: In function 'int read()':
council.cpp:11:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
   11 |     scanf("%d", &x);
      |     ~~~~~^~~~~~~~~~
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...