Submission #710783

#TimeUsernameProblemLanguageResultExecution timeMemory
710783pls33Tracks in the Snow (BOI13_tracks)C++17
47.50 / 100
2094 ms84176 KiB
// boi2013 day2 p2
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#pragma region dalykai
using p32 = pair<int, int>;
using p32u = pair<uint32_t, uint32_t>;
using p64 = pair<int64_t, int64_t>;
using p64u = pair<uint64_t, uint64_t>;
using vi16 = vector<int16_t>;
using vi16u = vector<uint16_t>;
using vi32 = vector<int>;
using vi32u = vector<uint32_t>;
using vi64 = vector<int64_t>;
using vi64u = vector<uint64_t>;
using vp32 = vector<p32>;
using vp32u = vector<p32u>;
using vp64 = vector<p64>;
using vp64u = vector<p64u>;
using vvi32 = vector<vi32>;
using vvi32u = vector<vi32u>;
using vvi64 = vector<vi64>;
using vvi64u = vector<vi64u>;
using vvp32 = vector<vp32>;
using vvp32u = vector<vp32u>;
using vvp64 = vector<vp64>;
using vvp64u = vector<vp64u>;
using f80 = long double;
#pragma endregion

using grid_t = vector<string>;

const vi16 dx = {1, -1, 0, 0};
const vi16 dy = {0, 0, 1, -1};

bool inside(p32 a, int row, int col)
{
    return a.first >= 0 && a.first < row &&
           a.second >= 0 && a.second < col;
}

// sauce: https://judge.yosupo.jp/submission/76471
template <uint32_t N>
struct Bitset
{
    using u64 = std::uint64_t;
    using u32 = std::uint32_t;
    using i32 = std::int32_t;

private:
    static constexpr u64 ONE = 1;
    static constexpr u64 ZERO = 0;
    static constexpr u64 ALL_MASK = ~ZERO;
    static constexpr u32 BITS = sizeof(u64) * CHAR_BIT;
    static constexpr u32 ALL = BITS - 1;
    static constexpr u32 CAPACITY = (N + BITS - 1) / BITS;
    static constexpr u32 REMAINING = N & ALL;
    static constexpr u64 CLEANUP_MASK = ~(ALL_MASK << REMAINING);
    u64 a[CAPACITY];
    /**
     * storage:
     * a[0] = bit_63,   ..., bit_0
     * a[1] = bit_127,  ..., bit_64
     * ...
     *
     * semantics of <<= and >>= : usual <<= and >>= semantics for u64
     */

    // NOTE: range violations are undefined behaviour and are unchecked
    struct reference
    {
    private:
        u32 pos;
        u64 *a;

    public:
        reference(u32 p, u64 *aa) : pos(p), a(aa) {}
        reference &operator=(bool x) noexcept
        {
            if (x)
                *a |= ONE << pos;
            else
                *a &= ~(ONE << pos);
            return *this;
        }
        reference &operator=(const reference &x) noexcept
        {
            if ((*x.a >> x.pos) & 1)
                *a |= ONE << pos;
            else
                *a &= ~(ONE << pos);
            return *this;
        }
        operator bool() const noexcept { return (*a >> pos) & 1; }
        bool operator~() const noexcept { return !((*a >> pos) & 1); }
        reference &flip() noexcept { *a ^= ONE << pos; }
    };

    inline void cleanup() noexcept { a[CAPACITY - 1] &= CLEANUP_MASK; }

public:
    constexpr Bitset() noexcept
    {
        static_assert(BITS == 64, "Won't work on this architecture");
        static_assert(N > 0, "Size of parameter should be a positive integer");
        reset();
    };

    constexpr Bitset(u64 x) noexcept : Bitset() { a[0] = x; };

    constexpr Bitset(const std::string &x) : Bitset()
    {
#ifdef DEBUG
        if (x.size() > N * BITS)
            throw std::out_of_range("String is too large to convert to Bitset");
#endif
        u32 cur_loc = 0;
        u32 bit = 0;
        for (const auto c : x)
        {
#ifdef DEBUG
            if (c != '0' && c != '1')
                throw std::invalid_argument(
                    "String should consist of only 0s and 1s");
#endif
            a[cur_loc] |= u64(c - '0') << (bit++);
            if (bit == BITS)
                bit = 0, ++cur_loc;
        }
    }

    constexpr Bitset(const Bitset &b)
    {
        std::copy(std::begin(b.a), std::end(b.a), std::begin(a));
    }

    bool operator==(const Bitset &b) const
    {
        return std::equal(std::begin(a), std::end(a), std::begin(b.a));
    }

    bool operator!=(const Bitset &b) const { return !(*this == b); }

    constexpr bool operator[](u32 pos) const
    {
#ifdef DEBUG
        assert(("Bitset index out of range, UB", pos >= 0 && pos < N));
#endif
        return (a[pos / BITS] >> (pos & ALL)) & 1;
    }

    reference operator[](u32 pos)
    {
#ifdef DEBUG
        assert(("Bitset index out of range, UB", pos >= 0 && pos < N));
#endif
        return reference(pos & ALL, a + pos / BITS);
    }

    std::string to_string() const
    {
        std::string s(N, '0');
        auto it = s.data() + N - 1;
        for (u32 i = 0; i < N; ++i)
            *(it--) += (a[i / BITS] >> (i & ALL)) & 1;
        return s;
    }

    u32 count() const noexcept
    {
        u32 ans = 0;
        for (u32 i = 0; i < CAPACITY; ++i)
            ans += __builtin_popcountll(a[i]);
        return ans;
    }

    u32 size() const noexcept { return N; }

#define IMPLEMENT(op)                             \
    Bitset &operator op(const Bitset &b) noexcept \
    {                                             \
        for (u32 i = 0; i < CAPACITY; ++i)        \
            a[i] op b.a[i];                       \
        return *this;                             \
    }
    IMPLEMENT(&=)
    IMPLEMENT(|=)
    IMPLEMENT(^=)
#undef IMPLEMENT
    Bitset &flip() noexcept
    {
        for (u32 i = 0; i < CAPACITY; ++i)
            a[i] = ~a[i];
        cleanup();
        return *this;
    }
    Bitset operator~() const noexcept { return Bitset(*this).flip(); }

    Bitset &operator<<=(u32 n) noexcept
    {
        if (n > N)
        {
            reset();
            return *this;
        }
        if (__builtin_expect(n != 0, 1))
        {
            const u32 loc = n / BITS;
            const u32 pos = n & ALL;
            if (pos == 0)
                for (u32 i = CAPACITY - 1; i != loc - 1; --i)
                    a[i] = a[i - loc];
            else
            {
                const u32 complement = BITS - pos;
                for (u32 i = CAPACITY - 1; i != loc - 1; --i)
                    a[i] = (a[i - loc] << pos) | (a[i - loc - 1] >> complement);
                a[loc] = a[0] << pos;
            }
            std::fill(std::begin(a), std::begin(a) + loc, 0);
            cleanup();
        }
        return *this;
    }

    // 01000 -> 00100
    Bitset &operator>>=(u32 n) noexcept
    {
        if (n > N)
        {
            reset();
            return *this;
        }
        if (__builtin_expect(n != 0, 1))
        {
            const u32 loc = n / BITS;
            const u32 pos = n & ALL;
            const u32 l = CAPACITY - 1 - loc;
            if (pos == 0)
                for (u32 i = 0; i <= l; ++i)
                    a[i] = a[i + loc];
            else
            {
                const u32 complement = BITS - pos;
                for (u32 i = 0; i < l; ++i)
                    a[i] = (a[i + loc] >> pos) | (a[i + loc + 1] << complement);
                a[l] = a[CAPACITY - 1] >> pos;
            }
            std::fill(std::begin(a) + l + 1, std::end(a), 0);
            cleanup();
        }
        return *this;
    }

    Bitset operator<<(u32 n) const noexcept { return Bitset(*this) <<= n; }
    Bitset operator>>(u32 n) const noexcept { return Bitset(*this) >>= n; }

    void reset() noexcept { std::fill(std::begin(a), std::end(a), 0); }

    void set() noexcept
    {
        std::fill(std::begin(a), std::end(a), ALL_MASK);
        cleanup();
    }

    // warning: these use ints and not u

    i32 find_first_set() const noexcept
    {
        for (i32 i = 0; i < (i32)CAPACITY; ++i)
        {
            u64 w = a[i];
            if (w)
                return i * BITS + __builtin_ctzll(w);
        }
        return N;
    }

    i32 find_first_unset() const noexcept
    {
        for (i32 i = 0; i < CAPACITY; ++i)
        {
            u64 w = ~a[i];
            if (w)
                return i * BITS + __builtin_ctzll(w);
        }
        return N;
    }

    i32 find_next_set(i32 i) const noexcept
    {
        ++i;
        if (i >= BITS * CAPACITY)
            return N;
        i32 loc = i / BITS;
        u64 w = a[loc] & (ALL_MASK << (i & ALL));
        if (w)
            return loc * BITS + __builtin_ctzll(w);
        for (++loc; loc < CAPACITY; ++loc)
        {
            w = a[loc];
            if (w)
                return loc * BITS + __builtin_ctzll(w);
        }
        return N;
    }

    i32 find_next_unset(i32 i) const noexcept
    {
        ++i;
        if (i >= BITS * CAPACITY)
            return N;
        i32 loc = i / BITS;
        u64 w = (~a[loc]) & (ALL_MASK << (i & ALL));
        if (w)
            return loc * BITS + __builtin_ctzll(w);
        for (++loc; loc < CAPACITY; ++loc)
        {
            w = ~a[loc];
            if (w)
                return loc * BITS + __builtin_ctzll(w);
        }
        return N;
    }

    i32 find_prev_set(i32 i) const noexcept
    {
        --i;
        if (i < 0)
            return -1;
        i32 loc = i / BITS;
        u64 w = a[loc] & (ALL_MASK >> (ALL ^ (i & ALL)));
        if (w)
            return loc * BITS + (ALL ^ __builtin_clzll(w));
        for (--loc; loc >= 0; --loc)
        {
            w = a[loc];
            if (w)
                return loc * BITS + (ALL ^ __builtin_clzll(w));
        }
        return -1;
    }

    i32 find_prev_unset(i32 i) const noexcept
    {
        --i;
        if (i < 0)
            return -1;
        i32 loc = i / BITS;
        u64 w = (~a[loc]) & (ALL_MASK >> (ALL ^ (i & ALL)));
        if (w)
            return loc * BITS + (ALL ^ __builtin_clzll(w));
        for (--loc; loc >= 0; --loc)
        {
            w = ~a[loc];
            if (w)
                return loc * BITS + (ALL ^ __builtin_clzll(w));
        }
        return -1;
    }

    i32 find_next_set(i32 i, i32 max_iter) const noexcept
    {
        ++i;
        if (i >= BITS * CAPACITY)
            return N;
        i32 loc = i / BITS;
        u64 w = a[loc] & (ALL_MASK << (i & ALL));
        if (w)
            return loc * BITS + __builtin_ctzll(w);
        int iter = 0;
        for (++loc; loc < CAPACITY && iter < max_iter; ++loc, ++iter)
        {
            w = a[loc];
            if (w)
                return loc * BITS + __builtin_ctzll(w);
        }
        return N;
    }

    i32 find_next_unset(i32 i, i32 max_iter) const noexcept
    {
        ++i;
        if (i >= BITS * CAPACITY)
            return N;
        i32 loc = i / BITS;
        u64 w = (~a[loc]) & (ALL_MASK << (i & ALL));
        if (w)
            return loc * BITS + __builtin_ctzll(w);
        int iter = 0;
        for (++loc; loc < CAPACITY && iter < max_iter; ++loc, ++iter)
        {
            w = ~a[loc];
            if (w)
                return loc * BITS + __builtin_ctzll(w);
        }
        return N;
    }

    i32 find_prev_set(i32 i, i32 max_iter) const noexcept
    {
        --i;
        if (i < 0)
            return -1;
        i32 loc = i / BITS;
        u64 w = a[loc] & (ALL_MASK >> (ALL ^ (i & ALL)));
        if (w)
            return loc * BITS + (ALL ^ __builtin_clzll(w));
        int iter = 0;
        for (--loc; loc >= 0 && iter < max_iter; --loc, ++iter)
        {
            w = a[loc];
            if (w)
                return loc * BITS + (ALL ^ __builtin_clzll(w));
        }
        return -1;
    }

    i32 find_prev_unset(i32 i, i32 max_iter) const noexcept
    {
        --i;
        if (i < 0)
            return -1;
        i32 loc = i / BITS;
        u64 w = (~a[loc]) & (ALL_MASK >> (ALL ^ (i & ALL)));
        if (w)
            return loc * BITS + (ALL ^ __builtin_clzll(w));
        int iter = 0;
        for (--loc; loc >= 0 && iter < max_iter; --loc, ++iter)
        {
            w = ~a[loc];
            if (w)
                return loc * BITS + (ALL ^ __builtin_clzll(w));
        }
        return -1;
    }

    i32 find_last_set() const noexcept
    {
        for (i32 i = CAPACITY - 1; i >= 0; --i)
        {
            u64 w = a[i];
            if (w)
                return i * BITS + (ALL ^ __builtin_clzll(w));
        }
        return -1;
    }

    i32 find_last_unset() const noexcept
    {
        for (i32 i = CAPACITY - 1; i >= 0; --i)
        {
            u64 w = ~a[i];
            if (w)
                return i * BITS + (ALL ^ __builtin_clzll(w));
        }
        return -1;
    }

    // i32 find_kth_set(i32 k) const noexcept {}

    // i32 find_kth_unset(i32 k) const noexcept {}

    // i32 find_kth_next_set(i32 i, i32 k) const noexcept {}

    // i32 find_kth_next_unset(i32 i, i32 k) const noexcept {}

    // i32 find_kth_last_set(i32 k) const noexcept {}

    // i32 find_kth_last_unset(i32 k) const noexcept {}

    // return [l, r)
    u64 slice(const u32 l, const u32 r) const
    {
#ifdef DEBUG
        assert(l <= N);
        assert(r <= N);
#endif
        if (l >= r)
            return 0;
        // 0 <= l < r <= N
        u32 i1 = l / BITS;
        u32 pos1 = l & ALL;
        u32 i2 = (r - 1) / BITS;
        u32 pos2 = (r - 1) & ALL;
        if (i1 == i2)
        {
            return (a[i1] & (ALL_MASK >> (ALL - pos2))) >> pos1;
        }
        else
        {
#ifdef DEBUG
            assert(i2 == i1 + 1);
#endif
            return (a[i1] >> pos1) |
                   ((a[i2] & (ALL_MASK >> (ALL - pos2))) << (BITS - pos1));
        }
    }

    std::string to_string_debug() const
    {
        std::string s(CAPACITY * BITS, '0');
        for (i32 i = 0; i < CAPACITY * BITS; ++i)
            s[CAPACITY * BITS - 1 - i] += (a[i / BITS] >> (i & ALL)) & 1;
        return s;
    }

    friend inline Bitset operator&(const Bitset &x, const Bitset &y) noexcept
    {
        Bitset result = x;
        result &= y;
        return result;
    }
    friend inline Bitset operator|(const Bitset &x, const Bitset &y) noexcept
    {
        Bitset result = x;
        result |= y;
        return result;
    }

    friend inline Bitset operator^(const Bitset &x, const Bitset &y) noexcept
    {
        Bitset result = x;
        result ^= y;
        return result;
    }
    friend std::ostream &operator<<(std::ostream &os, const Bitset &b)
    {
        return os << b.to_string();
    }
    friend std::istream &operator>>(std::istream &os, Bitset &b)
    {
        std::string s = "";
        os >> s;
        b = Bitset(s);
        return os;
    }
};

int main()
{
#ifndef _AAAAAAAAA
    ios_base::sync_with_stdio(false);
    cin.tie(0);
#else
    freopen("tracks.in", "r", stdin);
#ifndef __linux__
    atexit([]()
           {
        freopen("con", "r", stdin);
        system("pause"); });
#endif
#endif

    int row, col;
    cin >> row >> col;

    grid_t grid(row);
    for (auto &r : grid)
    {
        cin >> r;
    }

    vvi32 dist(row, vi32(col, INT_MAX));
    dist[0][0] = 1;
    Bitset<(int)8e6> now, later;
    now[0] = true;
    int count_now = 1, count_later = 0;

    int ans = 1;
    while (count_now)
    {
        int k = now.find_first_set();
        now[k] = false;
        count_now--;
        int r = k / col, c = k % col;

        for (int i = 0; i < (int)dx.size(); i++)
        {
            int n_r = r + dx[i];
            int n_c = c + dy[i];

            if (!inside({n_r, n_c}, row, col) ||
                dist[n_r][n_c] != INT_MAX ||
                grid[n_r][n_c] == '.')
            {
                continue;
            }

            if (grid[r][c] == grid[n_r][n_c])
            {
                dist[n_r][n_c] = dist[r][c];
                ans = max(ans, dist[n_r][n_c]);
                now[n_r * col + n_c] = true;
                count_now++;
            }
            else
            {
                dist[n_r][n_c] = dist[r][c] + 1;
                ans = max(ans, dist[n_r][n_c]);
                later[n_r * col + n_c] = true;
                count_later++;
            }
        }

        if (!count_now)
        {
            swap(now, later);
            swap(count_now, count_later);
        }
    }

    cout << ans << '\n';

    return 0;
}

Compilation message (stderr)

tracks.cpp:9: warning: ignoring '#pragma region dalykai' [-Wunknown-pragmas]
    9 | #pragma region dalykai
      | 
tracks.cpp:33: warning: ignoring '#pragma endregion ' [-Wunknown-pragmas]
   33 | #pragma endregion
      |
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...