Submission #1288959

#TimeUsernameProblemLanguageResultExecution timeMemory
1288959Gev2706PIN (CEOI10_pin)C++20
100 / 100
42 ms13912 KiB
// PIN pairs by exact Hamming distance D (n <= 5e4, len=4, D in [0..4])
// Counts, for each k=0..4, A_k = sum over subsets S (|S|=k) of pairs that agree on all positions in S.
// Then invert: if x_t = #pairs that agree on exactly t positions,
// A_k = sum_{t=k..4} C(t,k)*x_t  => solve for x_t and answer is x_{4-D}.
// Works for any alphabet; only equality matters.
//
// Input:
// n D
// n lines of 4-char PINs (digits/letters or any visible bytes; spaces not allowed in PIN)
// Output: number of pairs with Hamming distance exactly D
//
// O(n * 16) time, O(n) memory.

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, D;
    if (!(cin >> n >> D)) return 0;
    vector<string> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i];

    // 16 masks (4-bit). Bit i=1 means "keep position i"; 0 means wildcard.
    // Key encoding: high 8 bits store mask (for safety), remaining bytes pack kept chars in order i=0..3.
    // This guarantees uniqueness per (mask, kept-chars).
    array<unordered_map<unsigned long long, int>, 16> maps;
    for (int m = 0; m < 16; ++m) {
        // Heuristic reserve: about n / (#keys per mask). Keep it simple but safe.
        // For m==0, there is 1 key; for others, up to n distinct.
        if (m == 0) maps[m].reserve(1);
        else maps[m].reserve(min(n, 1<<16)); // avoid huge rehashes
    }

    auto make_key = [](const string& s, int mask)->unsigned long long {
        unsigned long long key = (unsigned long long)(mask & 0xFF) << 56; // mask in top 8 bits
        int shift = 0;
        for (int i = 0; i < 4; ++i) if (mask & (1<<i)) {
            key |= (unsigned long long)(unsigned char)s[i] << shift;
            shift += 8;
        }
        return key;
    };

    for (const string& s : a) {
        for (int m = 0; m < 16; ++m) {
            unsigned long long k = make_key(s, m);
            ++maps[m][k];
        }
    }

    long long A[5] = {0,0,0,0,0};
    auto popc = [](int x){ return __builtin_popcount((unsigned)x); };

    for (int m = 0; m < 16; ++m) {
        int k = popc(m);
        long long sum = 0;
        for (auto &it : maps[m]) {
            long long c = it.second;
            sum += c * (c - 1) / 2;
        }
        A[k] += sum;
    }

    // Invert:
    // x4 = A4
    // x3 = A3 - 4*x4
    // x2 = A2 - 3*x3 - 6*x4
    // x1 = A1 - 2*x2 - 3*x3 - 4*x4
    // x0 = A0 - x1 - x2 - x3 - x4
    long long x[5];
    x[4] = A[4];
    x[3] = A[3] - 4LL * x[4];
    x[2] = A[2] - 3LL * x[3] - 6LL * x[4];
    x[1] = A[1] - 2LL * x[2] - 3LL * x[3] - 4LL * x[4];
    x[0] = A[0] - x[1] - x[2] - x[3] - x[4];

    int t = 4 - D; // pairs that agree on exactly t positions
    if (t < 0 || t > 4) { cout << 0 << '\n'; return 0; }
    cout << x[t] << '\n';
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...