Submission #1291043

#TimeUsernameProblemLanguageResultExecution timeMemory
1291043vk3601hOsmosmjerka (COCI17_osmosmjerka)C++20
160 / 160
152 ms18580 KiB
#include <bits/stdc++.h>
using namespace std;

// 使用 64 位哈希(自然溢出)
using ull = unsigned long long;
using ll = long long;

// 8 个方向
const int DX[8] = {-1, 1, 0, 0, -1,  1, -1,  1};
const int DY[8] = { 0, 0,-1, 1, -1, -1,  1,  1};

ll gcdll(ll a, ll b) {
    while (b) {
        ll t = a % b;
        a = b;
        b = t;
    }
    return a;
}
ll lcmll(ll a, ll b) {
    return a / gcdll(a, b) * b;
}

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

    int M, N;
    ll K;
    cin >> M >> N >> K;

    vector<string> grid(M);   // 改名,不再叫 g
    for (int i = 0; i < M; ++i) cin >> grid[i];

    const ull P = 911382323ull;
    int MN = M * N;

    // 预处理 P^i
    vector<ull> powP(MN + 1);
    powP[0] = 1;
    for (int i = 1; i <= MN; ++i) {
        powP[i] = powP[i - 1] * P;
    }

    vector<ull> all_hashes;
    all_hashes.reserve(8ll * MN);

    for (int d = 0; d < 8; ++d) {
        int dx = DX[d], dy = DY[d];

        // 求沿此方向的周期长度 L_dir
        ll a, b;
        if (dx == 0) a = 1;
        else         a = M / gcdll(llabs(dx), (ll)M);

        if (dy == 0) b = 1;
        else         b = N / gcdll(llabs(dy), (ll)N);

        ll L_dir = lcmll(a, b);

        vector<char> visited(MN, 0);

        for (int start = 0; start < MN; ++start) {
            if (visited[start]) continue;

            vector<int> nodes;
            nodes.reserve((int)L_dir);

            int x = start / N, y = start % N;
            for (int step = 0; step < L_dir; ++step) {
                int id = x * N + y;
                visited[id] = 1;
                nodes.push_back(id);

                x += dx; if (x < 0) x += M; else if (x >= M) x -= M;
                y += dy; if (y < 0) y += N; else if (y >= N) y -= N;
            }

            int L = nodes.size();

            // 构造周期串前缀哈希
            vector<ull> pref(L + 1);
            pref[0] = 0;
            for (int i = 0; i < L; ++i) {
                int id = nodes[i];
                char ch = grid[id / N][id % N];
                ull v = (ull)(ch - 'a' + 1);
                pref[i + 1] = pref[i] * P + v;
            }

            ull H_S = pref[L];
            ull powL = powP[L];

            vector<pair<ull, ull>> basePow;
            vector<ll> lenPow;
            basePow.reserve(64);
            lenPow.reserve(64);

            basePow.push_back({H_S, powL});
            lenPow.push_back(L);

            while (lenPow.back() * 2 <= K) {
                ull h = basePow.back().first;
                ull p = basePow.back().second;
                ll len = lenPow.back();

                ull h2 = h * p + h;       // S^2 = S + S
                ull p2 = p * p;
                ll  l2 = len * 2;

                basePow.push_back({h2, p2});
                lenPow.push_back(l2);
            }

            auto pow_repeat = [&](ll t) {
                ull h_res = 0;
                ull p_res = 1;
                int bit = 0;
                while (t > 0) {
                    if (t & 1) {
                        ull h1 = h_res, p1 = p_res;
                        ull h2 = basePow[bit].first;
                        ull p2 = basePow[bit].second;
                        h_res = h1 * p2 + h2;
                        p_res = p1 * p2;
                    }
                    t >>= 1;
                    bit++;
                }
                return pair<ull, ull>(h_res, p_res);
            };

            // 为本周期上每个起点生成长度 K 的单词哈希
            for (int p = 0; p < L; ++p) {
                ll rem = K;
                ull h_cur = 0;
                ull p_cur = 1;

                // 先取 p 到周期末尾
                ll len1 = min(rem, (ll)L - p);
                if (len1 > 0) {
                    ull hFirst = pref[p + len1] - pref[p] * powP[len1];
                    ull pFirst = powP[len1];
                    h_cur = h_cur * pFirst + hFirst;
                    p_cur = p_cur * pFirst;
                    rem -= len1;
                }

                if (rem > 0) {
                    ll t_full = rem / L;
                    ll lenLast = rem % L;

                    if (t_full > 0) {
                        auto mid = pow_repeat(t_full);
                        h_cur = h_cur * mid.second + mid.first;
                        p_cur = p_cur * mid.second;
                    }
                    if (lenLast > 0) {
                        ull hLast = pref[lenLast];
                        ull pLast = powP[lenLast];
                        h_cur = h_cur * pLast + hLast;
                        p_cur = p_cur * pLast;
                    }
                }

                all_hashes.push_back(h_cur);
            }
        }
    }

    // 统计 X^2
    sort(all_hashes.begin(), all_hashes.end());
    ll num = 0;
    for (size_t i = 0; i < all_hashes.size(); ) {
        size_t j = i + 1;
        while (j < all_hashes.size() && all_hashes[j] == all_hashes[i]) j++;
        ll cnt = j - i;
        num += cnt * cnt;
        i = j;
    }

    ll T = 8ll * M * N;
    ll den = T * T;

    ll gg = gcdll(num, den);  // 不再叫 g,避免冲突
    num /= gg;
    den /= gg;

    cout << num << "/" << den << "\n";
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...