結果

問題 No.2507 Yet Another Subgraph Counting
ユーザー suisensuisen
提出日時 2023-08-22 16:01:49
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 247 ms / 2,000 ms
コード長 7,850 bytes
コンパイル時間 1,912 ms
コンパイル使用メモリ 189,552 KB
実行使用メモリ 4,720 KB
最終ジャッジ日時 2023-10-13 18:26:20
合計ジャッジ時間 6,653 ms
ジャッジサーバーID
(参考情報)
judge14 / judge11
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,348 KB
testcase_01 AC 2 ms
4,348 KB
testcase_02 AC 2 ms
4,352 KB
testcase_03 AC 1 ms
4,352 KB
testcase_04 AC 1 ms
4,352 KB
testcase_05 AC 9 ms
4,348 KB
testcase_06 AC 2 ms
4,352 KB
testcase_07 AC 1 ms
4,348 KB
testcase_08 AC 2 ms
4,348 KB
testcase_09 AC 1 ms
4,352 KB
testcase_10 AC 2 ms
4,352 KB
testcase_11 AC 9 ms
4,348 KB
testcase_12 AC 2 ms
4,356 KB
testcase_13 AC 2 ms
4,348 KB
testcase_14 AC 9 ms
4,356 KB
testcase_15 AC 1 ms
4,352 KB
testcase_16 AC 2 ms
4,352 KB
testcase_17 AC 9 ms
4,348 KB
testcase_18 AC 2 ms
4,348 KB
testcase_19 AC 4 ms
4,348 KB
testcase_20 AC 2 ms
4,348 KB
testcase_21 AC 2 ms
4,348 KB
testcase_22 AC 2 ms
4,348 KB
testcase_23 AC 9 ms
4,348 KB
testcase_24 AC 3 ms
4,352 KB
testcase_25 AC 24 ms
4,352 KB
testcase_26 AC 74 ms
4,352 KB
testcase_27 AC 9 ms
4,348 KB
testcase_28 AC 25 ms
4,352 KB
testcase_29 AC 2 ms
4,352 KB
testcase_30 AC 74 ms
4,352 KB
testcase_31 AC 247 ms
4,456 KB
testcase_32 AC 225 ms
4,720 KB
testcase_33 AC 9 ms
4,348 KB
testcase_34 AC 4 ms
4,348 KB
testcase_35 AC 9 ms
4,352 KB
testcase_36 AC 3 ms
4,352 KB
testcase_37 AC 229 ms
4,536 KB
testcase_38 AC 231 ms
4,464 KB
testcase_39 AC 227 ms
4,456 KB
testcase_40 AC 230 ms
4,540 KB
testcase_41 AC 233 ms
4,460 KB
testcase_42 AC 233 ms
4,448 KB
testcase_43 AC 73 ms
4,352 KB
testcase_44 AC 225 ms
4,520 KB
testcase_45 AC 9 ms
4,348 KB
testcase_46 AC 9 ms
4,352 KB
testcase_47 AC 226 ms
4,456 KB
testcase_48 AC 2 ms
4,348 KB
testcase_49 AC 227 ms
4,452 KB
testcase_50 AC 4 ms
4,352 KB
testcase_51 AC 73 ms
4,352 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <cassert>
#include <iostream>
#include <limits>
#include <utility>
#include <vector>

#include <immintrin.h>

namespace library {
    namespace bits {
        template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
        size_t bit_length(const T v) {
            if constexpr (std::numeric_limits<std::make_unsigned_t<T>>::digits <= 32) {
                return 32 - __builtin_clz(v);
            } else {
                return 64 - __builtin_clzll(v);
            }
        }
        template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
        size_t popcount(const T v) {
            if constexpr (std::numeric_limits<std::make_unsigned_t<T>>::digits <= 32) {
                return __builtin_popcount(v);
            } else {
                return __builtin_popcountll(v);
            }
        }
        template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
        size_t count_tz(const T v) {
            if constexpr (std::numeric_limits<std::make_unsigned_t<T>>::digits <= 32) {
                return __builtin_ctz(v);
            } else {
                return __builtin_ctzll(v);
            }
        }
        template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
        __attribute__((target("bmi2"))) T pdep(const T src, const T mask) {
            /*
            T dst = 0;
            for (size_t i = 0, j = 0; i < BIT_NUM; ++i) {
                if ((mask >> i) & 1) dst |= ((src >> j) & 1) << i, ++j;
            }
            return dst;
            */
            if constexpr (std::numeric_limits<std::make_unsigned_t<T>>::digits <= 32) {
                return _pdep_u32(src, mask);
            } else {
                return _pdep_u64(src, mask);
            }
        }
    }

    namespace subset_transform {
        template <typename T> void zeta(std::vector<T>& x) {
            const size_t n = x.size();
            for (size_t b = 1; b < n; b *= 2) for (size_t l = 0; l < n; l += 2 * b) for (size_t i = l; i < l + b; ++i) {
                x[i + 1 * b] += x[i + 0 * b];
            }
        }
        template <typename T> void mobius(std::vector<T>& x) {
            const size_t n = x.size();
            for (size_t b = 1; b < n; b *= 2) for (size_t l = 0; l < n; l += 2 * b) for (size_t i = l; i < l + b; ++i) {
                x[i + 1 * b] -= x[i + 0 * b];
            }
        }
    }

    namespace set_power_series {
        namespace details {
            template <typename T> struct polynomial : std::vector<T> {
                using std::vector<T>::vector;
                polynomial& operator+=(const polynomial& q) {
                    for (size_t i = 0; i < q.size(); ++i) (*this)[i] += q[i];
                    return *this;
                }
                polynomial& operator-=(const polynomial& q) {
                    for (size_t i = 0; i < q.size(); ++i) (*this)[i] -= q[i];
                    return *this;
                }
                polynomial& operator*=(const polynomial& q) {
                    const size_t n = this->size();
                    polynomial r(n);
                    for (size_t i = 0; i < n; ++i) for (size_t j = 0; i + j < n; ++j) r[i + j] += (*this)[i] * q[j];
                    return *this = std::move(r);
                }
                polynomial operator+(const polynomial& q) { polynomial p = *this; p += q; return p; }
                polynomial operator-(const polynomial& q) { polynomial p = *this; p -= q; return p; }
                polynomial operator*(const polynomial& q) { polynomial p = *this; p *= q; return p; }
            };
            template <typename T> std::vector<polynomial<T>> add_rank(const std::vector<T>& a) {
                const size_t n = a.size();
                std::vector fs(n, polynomial<T>(bits::count_tz(n) + 1, T{ 0 }));
                for (size_t i = 0; i < n; ++i) fs[i][bits::popcount(i)] = a[i];
                return fs;
            }
            template <typename T> std::vector<T> remove_rank(const std::vector<polynomial<T>>& polys) {
                const size_t n = polys.size();
                std::vector<T> a(n);
                for (size_t i = 0; i < n; ++i) a[i] = polys[i][bits::popcount(i)];
                return a;
            }
        }
        
        template <typename T> std::vector<T> subset_convolution(const std::vector<T>& a, const std::vector<T>& b) {
            const size_t n = a.size();
            auto ra = details::add_rank(a);
            auto rb = details::add_rank(b);
            subset_transform::zeta(ra);
            subset_transform::zeta(rb);
            for (size_t i = 0; i < n; ++i) ra[i] *= rb[i];
            subset_transform::mobius(ra);
            return details::remove_rank(ra);
        }
        template <typename T> std::vector<T> subset_exp(const std::vector<T>& f) {
            assert(f[0] == 0);
            const size_t n = bits::bit_length(f.size()) - 1;
            std::vector<T> g{ 1 };
            for (size_t i = 0; i < n; ++i) {
                std::vector<T> h = subset_convolution(g, std::vector<T>(f.begin() + (1 << i), f.begin() + (1 << (i + 1))));
                std::move(h.begin(), h.end(), std::back_inserter(g));
            }
            return g;
        }
    }
}

using vertex = size_t;
using vertex_set = size_t;
using edge = std::pair<vertex, vertex>;
using Int = uint64_t;

std::vector<Int> count_cycles(const size_t n, const size_t, const std::vector<edge>& edges) {
    std::vector adj(n, std::vector<vertex>{});
    for (const auto& [u, v] : edges) adj[u].push_back(v), adj[v].push_back(u);

    std::vector dp(1u << n, std::vector<Int>(n));
    for (size_t v = 0; v < n; ++v) {
        dp[1u << v][v] = 1;
    }
    std::vector<Int> c(1u << n);
    for (vertex_set s = 1; s < 1u << n; ++s) {
        const vertex start = library::bits::count_tz(s);
        for (vertex cur = 0; cur < n; ++cur) for (const vertex nxt : adj[cur]) {
            if (start == nxt) {
                c[s] += dp[s][cur];
            } else if (start < nxt and not ((s >> nxt) & 1)) {
                const vertex_set nxt_s = s | (1u << nxt);
                dp[nxt_s][nxt] += dp[s][cur];
            }
        }
    }
    for (vertex_set s = 1; s < 1u << n; ++s) {
        const size_t card = library::bits::popcount(s);
        if (card == 1) c[s] = 1;
        if (card == 2) c[s] = 0;
        if (card >= 3) c[s] /= 2;
    }
    return c;
}

Int solve(const size_t n, const size_t m, const std::vector<edge>& edges) {
    // e[S] := # edges connecting vertices in S.
    std::vector<Int> e(1u << n);
    for (const auto& [u, v] : edges) ++e[(1u << u) | (1u << v)];
    library::subset_transform::zeta(e);

    using sps = std::vector<Int>;

    const sps c = count_cycles(n, m, edges);

    sps f(1u << n);
    for (vertex_set C = 1; C < 1u << n; ++C) {
        // max C
        const vertex t = library::bits::bit_length(C) - 1;
        // { 0, ..., t } - C
        const vertex_set S = ((1u << (t + 1)) - 1) ^ C;
        const size_t k = library::bits::popcount(S);
        sps g(1u << k);
        for (vertex_set A = 0; A < 1u << k; ++A) {
            const vertex_set T = library::bits::pdep(A, S);
            g[A] = f[T] * (e[T | C] - e[T] - e[C]);
        }
        const sps h = library::set_power_series::subset_exp(g);
        for (vertex_set A = 0; A < 1u << k; ++A) {
            const vertex_set X = library::bits::pdep(A, S) | C;
            f[X] += c[C] * h[A];
        }
    }
    return library::set_power_series::subset_exp(f).back();
}

int main() {
    size_t n, m;
    std::cin >> n >> m;
    std::vector<edge> edges(m);
    for (auto& [u, v] : edges) {
        std::cin >> u >> v;
        --u, --v;
    }
    std::cout << solve(n, m, edges) << '\n';
}
0