ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

loj2540. 「PKUWC2018」随机算法

2019-12-09 09:53:53  阅读:226  来源: 互联网

标签:__ 加入 int loj2540 popcount ret 算法 PKUWC2018 mod


题意

略。

题解

听说考场上暴力搜出独立集有90分
这道题的状态还是挺难找的。
初始排列为空。考虑设\(f_{s, i}\)表示当前状态,独立集为\(s\),已经不在独立集里面(即与\(s\)中的点有连边)且还没有加入排列的点数为\(i\)。
则有初始状态\(f_{0, 0} = 1\)。
考虑转移,如果某一个点可以加入这个独立集,则:
\[ f_{s \cup \{x\}, i + \text{new}(x, s)} += f_{s, i} \ (x \notin s) \]
其中\(new(x, s)\)代表的是与\(x\)有连边,并且不属于\(s\)且不与\(s\)中任何点有连边的点的个数。
这个操作代表将\(x\)加入排列。
只有这样一种操作是不够的,考虑要把已经不在独立集里面且还没有加入排列的点加入排列,如果有\(i\)个这样的点,那么这次可以选择任何一个加入。

\[ f_{s, i - 1} += f_{s, i} \]
考虑到转移一定构成了一个DAG(先按集合\(s\)的偏序,再按点数\(i\)的偏序),所以是没问题的。
但是转移的时候要注意后一种操作是可以不断地做的,所以\(i\)的枚举方向是从\(n\)到\(1\)。
复杂度\(\mathcal O(2 ^ n n ^ 2)\)。

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;

const int N = 20, M = 1 << 20, mod = 998244353;
int n, m, c, ans, e[M], d[N][M], t[M], f[N][M];
int power (int x, int y) {
    int ret = 1;
    for ( ; y; y >>= 1, x = 1ll * x * x % mod) {
        if (y & 1) {
            ret = 1ll * ret * x % mod;
        }
    }
    return ret;
}
void U (int &x, int y) {
    if ((x += y) >= mod) {
        x -= mod;
    }
}
int main () {
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        e[1 << i] = 1 << i;
    }
    for (int i = 1, x, y; i <= m; ++i) {
        cin >> x >> y, --x, --y;
        e[1 << x] |= 1 << y, e[1 << y] |= 1 << x;
    }
    m = 1 << n;
    for (int i = 0; i < n; ++i) {
        for (int s = 0; s < m; ++s) {
            if (s >> i & 1) {
                e[s] |= e[s ^ 1 << i];
            }
        }
    }
    for (int i = 0; i < n; ++i) {
        for (int s = 0; s < m; ++s) {
            if (~e[s] >> i & 1) {
                d[i][s] = __builtin_popcount(e[s] | e[1 << i] ^ (1 << i)) - __builtin_popcount(e[s]);
            }
        }
    }
    f[0][0] = 1;
    for (int s = 0; s < m; ++s) {
        for (int i = n; i; --i) {
            U(f[i - 1][s], 1ll * f[i][s] * i % mod);
        }
        for (int i = n; ~i; --i) {
            if (f[i][s]) {
                for (int x = 0; x < n; ++x) {
                    if (~e[s] >> x & 1) {
                        U(f[i + d[x][s]][s | 1 << x], f[i][s]);
                    }
                }
            }
        }
    }
    for (int s = 0; s < m; ++s) {
        if (f[0][s]) {
            if (__builtin_popcount(s) > c) {
                c = __builtin_popcount(s), ans = 0;
            }
            if (__builtin_popcount(s) == c) {
                U(ans, f[0][s]);
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        ans = 1ll * ans * power(i, mod - 2) % mod;
    }
    cout << ans << endl;
    return 0;
}

标签:__,加入,int,loj2540,popcount,ret,算法,PKUWC2018,mod
来源: https://www.cnblogs.com/psimonw/p/12009216.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有