Submission #520263

# Submission time Handle Problem Language Result Execution time Memory
520263 2022-01-29T04:17:12 Z KoD Trener (COCI20_trener) C++17
110 / 110
1181 ms 2372 KB
#line 1 "main.cpp"
#include <bits/stdc++.h>
#define ENABLE_AVX2
#line 3 "/Users/kodamankod/Desktop/CppProcon/Library/proconlib/utility/int_alias.cpp"

using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
using i128 = __int128_t;
using u128 = __uint128_t;
#line 3 "/Users/kodamankod/Desktop/CppProcon/Library/proconlib/utility/rep.cpp"

class Range {
    struct Iter {
        int itr;
        constexpr Iter(const int pos) noexcept : itr(pos) {}
        constexpr void operator++() noexcept { ++itr; }
        constexpr bool operator!=(const Iter& other) const noexcept { return itr != other.itr; }
        constexpr int operator*() const noexcept { return itr; }
    };
    const Iter first, last;

  public:
    explicit constexpr Range(const int first, const int last) noexcept : first(first), last(std::max(first, last)) {}
    constexpr Iter begin() const noexcept { return first; }
    constexpr Iter end() const noexcept { return last; }
};

constexpr Range rep(const int l, const int r) noexcept { return Range(l, r); }
constexpr Range rep(const int n) noexcept { return Range(0, n); }
#line 5 "/Users/kodamankod/Desktop/CppProcon/Library/proconlib/random/xorshift.cpp"

u64 xorshift() {
    static u64 state = std::chrono::system_clock::now().time_since_epoch().count();
    state ^= state << 7;
    state ^= state >> 9;
    return state;
}
#line 4 "/Users/kodamankod/Desktop/CppProcon/Library/proconlib/random/rand_int.cpp"

template <class T> T rand_int(const T& min, const T& max) {
    static std::default_random_engine gen(xorshift());
    return std::uniform_int_distribution<T>(min, max)(gen);
}
#line 9 "/Users/kodamankod/Desktop/CppProcon/Library/proconlib/container/polynomial_hash.cpp"

struct PolynomialHashOperations {
    static inline constexpr u64 MOD = ((u64)1 << 61) - 1;
    static constexpr u64 sum(u64 a, const u64 b) { return (a += b) >= MOD ? a - MOD : a; }
    static constexpr u64 difference(u64 a, const u64 b) { return (a += MOD - b) >= MOD ? a - MOD : a; }
    static constexpr u64 product(const u64 a, const u64 b) {
        u128 ret = (u128)a * b;
        ret = (ret >> 61) + (ret & MOD);
        return ret >= MOD ? ret - MOD : ret;
    }
};

template <int ID> struct PolynomialHashBase {
    static inline const u64 BASE = rand_int<u64>(0, PolynomialHashOperations::MOD - 1);
    static u64 base_pow(const int n) {
        static std::vector<u64> vec;
        if (vec.empty()) vec = {1};
        while ((int)vec.size() <= n) vec.push_back(PolynomialHashOperations::product(vec.back(), BASE));
        return vec[n];
    }
};

template <class T, int ID = -1, std::enable_if_t<std::is_integral_v<T>>* = nullptr> class PolynomialHash {
    using Oper = PolynomialHashOperations;
    using Base = PolynomialHashBase<ID>;

    std::vector<u64> hash;
    std::vector<T> data;

  public:
    PolynomialHash() : PolynomialHash(std::vector<T>()) {}
    explicit PolynomialHash(const std::vector<T>& vec) : data(vec) {
        const int size = data.size();
        hash = std::vector<u64>(size + 1);
        for (const int i : rep(size)) {
            assert(0 <= data[i] and (u64) data[i] < Oper::MOD);
            hash[i + 1] = Oper::sum(Oper::product(Base::BASE, hash[i]), (u64)data[i]);
        }
    }

    int size() const { return data.size(); }
    const std::vector<T>& get() const { return data; }

    u64 fold() const { return hash.back(); }
    u64 fold(const int l, const int r) const {
        assert(0 <= l and l <= r and r <= size());
        return Oper::difference(hash[r], Oper::product(hash[l], Base::base_pow(r - l)));
    }

    void concat(const PolynomialHash& other) {
        hash.reserve(hash.size() + other.size());
        u64 val = hash.back();
        for (const int i : rep(other.size())) {
            val = Oper::product(val, Base::BASE);
            hash.push_back(Oper::sum(val, other.hash[i + 1]));
        }
        data.reserve(data.size() + other.size());
        std::copy(other.data.cbegin(), other.data.cend(), std::back_inserter(data));
    }
};
#line 3 "/Users/kodamankod/Desktop/CppProcon/Library/proconlib/math/rem_euclid.cpp"

template <class T> constexpr T rem_euclid(T value, const T& mod) {
    assert(mod > 0);
    return (value %= mod) >= 0 ? value : value + mod;
}
#line 2 "/Users/kodamankod/Desktop/CppProcon/Library/proconlib/math/totient.cpp"

template <class T> constexpr T totient(T x) {
    T ret = x;
    for (T i = 2; i * i <= x; ++i) {
        if (x % i == 0) {
            ret /= i;
            ret *= i - 1;
            while (x % i == 0) x /= i;
        }
    }
    if (x > 1) {
        ret /= x;
        ret *= x - 1;
    }
    return ret;
}
#line 7 "/Users/kodamankod/Desktop/CppProcon/Library/proconlib/math/static_modint.cpp"

template <u32 MOD, std::enable_if_t<((u32)1 <= MOD and MOD <= ((u32)1 << 31))>* = nullptr> class StaticModint {
    using Self = StaticModint;

    static inline constexpr u32 PHI = totient(MOD);
    u32 v;

  public:
    static constexpr u32 mod() noexcept { return MOD; }

    template <class T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
    static constexpr T normalize(const T& x) noexcept {
        return rem_euclid<std::common_type_t<T, i64>>(x, MOD);
    }

    constexpr StaticModint() noexcept : v(0) {}
    template <class T> constexpr StaticModint(const T& x) noexcept : v(normalize(x)) {}
    template <class T> static constexpr Self raw(const T& x) noexcept {
        Self ret;
        ret.v = x;
        return ret;
    }

    constexpr u32 val() const noexcept { return v; }
    constexpr Self neg() const noexcept { return raw(v == 0 ? 0 : MOD - v); }
    constexpr Self inv() const noexcept { return pow(PHI - 1); }
    constexpr Self pow(u64 exp) const noexcept {
        Self ret(1), mult(*this);
        for (; exp > 0; exp >>= 1) {
            if (exp & 1) ret *= mult;
            mult *= mult;
        }
        return ret;
    }

    constexpr Self operator-() const noexcept { return neg(); }
    constexpr Self operator~() const noexcept { return inv(); }

    constexpr Self operator+(const Self& rhs) const noexcept { return Self(*this) += rhs; }
    constexpr Self& operator+=(const Self& rhs) noexcept {
        if ((v += rhs.v) >= MOD) v -= MOD;
        return *this;
    }

    constexpr Self operator-(const Self& rhs) const noexcept { return Self(*this) -= rhs; }
    constexpr Self& operator-=(const Self& rhs) noexcept {
        if (v < rhs.v) v += MOD;
        v -= rhs.v;
        return *this;
    }

    constexpr Self operator*(const Self& rhs) const noexcept { return Self(*this) *= rhs; }
    constexpr Self& operator*=(const Self& rhs) noexcept {
        v = (u64)v * rhs.v % MOD;
        return *this;
    }

    constexpr Self operator/(const Self& rhs) const noexcept { return Self(*this) /= rhs; }
    constexpr Self& operator/=(const Self& rhs) noexcept { return *this *= rhs.inv(); }

    constexpr bool operator==(const Self& rhs) const noexcept { return v == rhs.v; }
    constexpr bool operator!=(const Self& rhs) const noexcept { return v != rhs.v; }
    friend std::ostream& operator<<(std::ostream& stream, const Self& rhs) { return stream << rhs.v; }
};

using Modint1000000007 = StaticModint<1000000007>;
using Modint998244353 = StaticModint<998244353>;
#line 7 "main.cpp"

using std::vector;
using std::array;
using std::pair;
using std::tuple;

using Fp = Modint1000000007;

void main_() {   
    int N, K;
    std::cin >> N >> K;
    vector<Fp> dp(K, 1);
    vector<u64> hash(K);
    for (auto& x : hash) {
        char c;
        std::cin >> c;
        x = PolynomialHash(vector<char>{c}).fold();
    }
    for (const int i : rep(2, N + 1)) {
        vector<Fp> next(K);
        vector<u64> next_hash(K);
        for (const int j : rep(K)) {
            vector<char> s(i);
            for (auto& x : s) {
                std::cin >> x;
            }
            const PolynomialHash p(s);
            for (const int k : rep(K)) {
                if (p.fold(0, i - 1) == hash[k] or p.fold(1, i) == hash[k]) {
                    next[j] += dp[k];
                }
            }
            next_hash[j] = p.fold();
        }
        dp = std::move(next);
        hash = std::move(next_hash);
    }
    std::cout << std::accumulate(dp.begin(), dp.end(), Fp(0)) << '\n';
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    main_();
    return 0;
}
# Verdict Execution time Memory Grader output
1 Correct 1 ms 208 KB Output is correct
2 Correct 0 ms 316 KB Output is correct
3 Correct 0 ms 316 KB Output is correct
4 Correct 0 ms 208 KB Output is correct
# Verdict Execution time Memory Grader output
1 Correct 8 ms 336 KB Output is correct
2 Correct 8 ms 336 KB Output is correct
3 Correct 8 ms 456 KB Output is correct
4 Correct 8 ms 332 KB Output is correct
5 Correct 8 ms 364 KB Output is correct
6 Correct 8 ms 432 KB Output is correct
7 Correct 7 ms 336 KB Output is correct
# Verdict Execution time Memory Grader output
1 Correct 1 ms 208 KB Output is correct
2 Correct 0 ms 316 KB Output is correct
3 Correct 0 ms 316 KB Output is correct
4 Correct 0 ms 208 KB Output is correct
5 Correct 8 ms 336 KB Output is correct
6 Correct 8 ms 336 KB Output is correct
7 Correct 8 ms 456 KB Output is correct
8 Correct 8 ms 332 KB Output is correct
9 Correct 8 ms 364 KB Output is correct
10 Correct 8 ms 432 KB Output is correct
11 Correct 7 ms 336 KB Output is correct
12 Correct 1037 ms 2364 KB Output is correct
13 Correct 1036 ms 2236 KB Output is correct
14 Correct 1086 ms 2244 KB Output is correct
15 Correct 1094 ms 2360 KB Output is correct
16 Correct 747 ms 2240 KB Output is correct
17 Correct 1126 ms 2364 KB Output is correct
18 Correct 1139 ms 2244 KB Output is correct
19 Correct 1181 ms 2240 KB Output is correct
20 Correct 1177 ms 2244 KB Output is correct
21 Correct 1132 ms 2236 KB Output is correct
22 Correct 760 ms 2372 KB Output is correct