• PKUWC 2018 随机算法


    PKUWC 2018 随机算法

    [made by Ameiyo ]


    题目连接

    用 $ f[i][s] $ 表示已经有 $ i $ 个点在排列里面,最大独立集的集合为 $ s $ ,这样的方案数。

    对于当前不能加入最大独立集的点,在之后仍然不能加入,所以这些点可以被视为相同点,当做消耗品一样使用即可。

    而可以加入的点,即加入后会使最大独立集变大的点,就直接放进 $ s $ 就行了。

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define ll long long
    #define reg register
    #define rep(i, a, b) for (reg int i = (a), i##end = (b); i <= i##end; ++i)
    #define dep(i, a, b) for (reg int i = (a), i##end = (b); i >= i##end; --i)
    
    template <typename _typer> inline _typer read() {
        _typer init = 0;
        char ch = getchar(), k = 0;
        for ( ; !isdigit(ch); ch = getchar()) k = (ch == '-');
        for ( ; isdigit(ch); ch = getchar())
            init = (init << 3) + (init << 1) + (ch ^ 48);
        return k ? -init : init;
    }
    const ll N = 25, INF = 1e9;
    const ll M = (1 << 20), Mod = 998244353;
    
    int n, m, G[N][N];
    int tp[M], mk[N][M];
    int f[N][M];
    
    int Pow(int x, int k) {
        int ans = 1;
        for ( ; k > 0; x = 1ll * x * x % Mod, k >>= 1)
            ((k & 1) && (ans = 1ll * ans * x % Mod));
        return ans;
    }
    
    void Add(int &x, int y) { ((x += y) >= Mod && (x -= Mod)); }
    
    int main() {
        n = read<int>(), m = read<int>();
        rep (i, 0, m - 1) {
            int x = read<int>() - 1, y = read<int>() - 1;
            G[x][y] = G[y][x] = true;
        }
    
        rep (i, 0, n - 1) tp[1 << i] = i, mk[i][0] = true;
        rep (i, 0, n - 1) rep (s, 1, (1 << n) - 1) if (!(s & (1 << i)))
            mk[i][s] = (mk[i][s & (s - 1)] && !G[i][tp[s & -s]]);
    
        f[0][0] = 1;
        // 不能放的点一直都不能放,所以可以算是一类点,就是把这部分处理掉就行了
        rep (i, 0, n - 1) rep (s, 0, (1 << n) - 1) if (f[i][s]) {
            reg int tmp = f[i][s], res = 0;
            rep (j, 0, n - 1) if (mk[j][s])
                ++res, Add(f[i + 1][s | (1 << j)], tmp);
            Add(f[i + 1][s], 1ll * tmp * (n - i - res) % Mod);
        }
    
        int Ans = 0, tot = 1, mx = 0;
        rep (i, 1, n) tot = 1ll * tot * i % Mod;
        rep (s, 0, (1 << n) - 1) if (f[n][s]) {
            int cnt = 0;
            for (int x = s; x > 0; x &= (x - 1)) ++cnt;
            if (cnt > mx) Ans = f[n][s], mx = cnt;
            else if (cnt == mx) Add(Ans, f[n][s]);
        }
    
    //     cerr << Ans << endl;
    
        printf("%lld
    ", 1ll * Ans * Pow(tot, Mod - 2) % Mod);
        return 0;
    }
    

    注意洛谷上卡内存, $ mk $ 数组开不了,但是 $ O(2 ^ n * n ^ 3) $ 可以过。。。


    [in 2019.12.8 ]

  • 相关阅读:
    redis持久化RDB与AOF
    oracle PL/SQL习题
    pl/sql中的三种循环
    转 Oracle Cursor用法总结
    Oracle与MySQL的SQL语句区别
    安装mysql 遇到最后一步卡死解决方案
    Oracle安装
    mysql安装
    sql语句的优先级
    MVC设计模式
  • 原文地址:https://www.cnblogs.com/Ameiyo/p/12004561.html
Copyright © 2020-2023  润新知