【UR #17】滑稽树前做游戏

题目链接

分析

据说本来这题吉老师打算出给zjoi的 233
这里写图片描述

代码

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) 
{
    char c = getchar();
    bool f = false;
    for (x = 0; !isdigit(c); c = getchar()) 
    {
        if (c == '-') {
            f = true;
        }
    }
    for (; isdigit(c); c = getchar()) 
    {
        x = x * 10 + c - '0';
    }
    if (f) 
    {
        x = -x;
    }
}

template <typename T> inline bool CheckMax(T &a, const T &b) 
{
    return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) 
{
    return a > b ? a = b, true : false;
}

const int N = 30;
const int M = 5000005;
const int mod = 998244353;

int n, m, tim, tot, adj[N], inp[N], inv[N], vis[N], c[N][N];
unordered_map <int, int> idx;
vector <int> ply[M];

inline int DFS(int x, int s) 
{
    int ret = 1 << x;
    vis[x] = tim;
    for (int i = 0; i < n; ++i) {
        if (((s & adj[x]) >> i & 1) && vis[i] != tim) 
        {
            ret |= DFS(i, s);
        }
    }
    return ret;
}

inline void Add(vector <int> &a, vector <int> b) 
{
    for (; a.size() < b.size(); a.pb(0));
    for (int i = 0; i < b.size(); ++i) 
    {
        a[i] = (a[i] + b[i]) % mod;
    }
}

inline vector <int> Mul(vector <int> a, vector <int> b) 
{
    vector <int> c(a.size() + b.size() - 1, 0);
    for (int i = 0; i < a.size(); ++i) 
    {
        for (int j = 0; j < b.size(); ++j) 
        {
            c[i + j] = (1LL * a[i] * b[j] + c[i + j]) % mod;
        }
    }
    return c;
}

inline vector <int> Int(vector <int> a) 
{
    vector <int> b(a.size() + 1, 0);
    for (int i = 0; i < a.size(); ++i) 
    {
        b[i + 1] = 1LL * a[i] * inv[i + 1] % mod;
    }
    return b;
}

inline void Update(vector <int> &a, vector <int> b, int d) 
{
    vector <int> e = Int(Mul(b, vector <int> (c[d], c[d] + d + 1)));
    Add(a, e);
    for (int i = 1; i < e.size(); ++i) 
    {
        a[0] = (a[0] - 1LL * e[i] * inp[i] % mod + mod) % mod;
    }
}

inline int Solve(int s) 
{
    if (idx[s]) 
    {
        return idx[s];
    }
    if (!s) 
    {
        ply[++tot] = {1};
        return tot;
    }
    int x = idx[s] = ++tot, y = __builtin_popcount(s);
    vector <int> com;
    ++tim;
    for (int i = 0; i < n; ++i) 
    {
        if ((s >> i & 1) && vis[i] != tim) 
        {
            com.pb(DFS(i, s));
        }
    }
    if (com.size() > 1) 
    {
        ply[x] = {1};
        for (int i = 0; i < com.size(); ++i) 
        {
            ply[x] = Mul(ply[x], ply[Solve(com[i])]);
        }
        return x;
    }
    ply[x].resize(y + 1), ply[x][0] = inp[y];
    for (int i = 0; i < n; ++i) 
    {
        if (s >> i & 1) 
        {
            Update(ply[x], ply[Solve((s ^ adj[i]) & s)], __builtin_popcount(s & adj[i]) - 1);
        }
    }
    return x;
}

int main() 
{
    Read(n), Read(m), inv[0] = inv[1] = inp[0] = 1, inp[1] = mod + 1 >> 1;
    for (int i = 2; i <= n + 1; ++i) 
    {
        inp[i] = 1LL * inp[i - 1] * inp[1] % mod;
        inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
    }
    for (int i = 0; i <= n; ++i) 
    {
        c[i][0] = 1;
        for (int j = 1; j <= i; ++j) 
        {
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
        }
    }
    for (int i = 0; i <= n; ++i) 
    {
        for (int j = 0; j <= i; ++j) 
        {
            if (j & 1) 
            {
                c[i][j] = (mod - c[i][j]) % mod;
            }
        }
    }
    for (int i = 1, x, y; i <= m; ++i) 
    {
        Read(x), Read(y), --x, --y;
        adj[x] |= 1 << y, adj[y] |= 1 << x;
    }
    for (int i = 0; i < n; ++i) 
    {
        adj[i] |= 1 << i;
    }
    vector <int> ans = ply[Solve((1 << n) - 1)];
    int ret = 0;
    for (int i = 0; i <= n; ++i) 
    {
        ret = (1LL * ans[i] * inv[n + 1] + ret) % mod;
        ret = (1LL * ans[i] * inv[n - i + 1] % mod * ((1 << n - i + 1) - 1) + ret) % mod;
    }
    printf("%d\n", (mod + 2 - ret) % mod);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值