CF1193A Amusement Park

传送门1

传送门2

被 A 题爆踩,没救了...

哦原来是 CEOI 啊,还有救还有救...


思路

首先这 \(2^m\) 张图中,如果它是 DAG,那么他们字典序最小的拓扑序两两不同

因为假设反转 \((u,v)\),那么 \(u,v\) 的入度关系就会改变,他俩的拓扑序一定会反过来

考虑将问题化简:对于一个 DAG,将它所有的边反向也是一个 DAG,而且这两个 DAG 的贡献和为 \(m\);于是问题就变成无向图给边定向,求方案数 \(\times~m~/~2\)

我们设 \(dp[S]\) 表示确定了 \(S\) 中这些点构成的 DAG 的个数,考虑将 \(T\) 这些点加入

为了确保 \(S+T\) 依旧是个 DAG,我们加入的 \(T\) 必须要是一个独立集

实际上,由 \(dp[S]\) 转移到 \(dp[S+T]\) 代表 \(S\) 中的点都指向 \(T\) 中的点

因为 \(T\) 中的点可以分批加入,我们需要容斥,即有转移:

\[dp[S+T]=(-1)^{|T|+1}dp[S],~S\cap T=\oslash \]

时间复杂度为 \(O(3^n+2^nm)\)


代码

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = r[i].nxt)
inline int reads()
{
    int sign = 1, re = 0; char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
    while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
    return sign * re;
}
namespace MOD
{
    const int mod = 998244353;
    inline int add(int a, int b) {return a + b >= mod ? a + b - mod : a + b;}
    inline int mul(int a, int b) {return 1ll * a * b % mod;}
    inline int sub(int a, int b) {return a - b < 0 ? a - b + mod : a - b;}
} using namespace MOD;
int n, m, w, a[155], b[155];
int f[1 << 18], t[1 << 18]; bool idp[1 << 18];
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    n = reads(), m = reads(), w = (1 << n) - 1;
    FOR(i, 1, m) a[i] = reads() - 1, b[i] = reads() - 1;
    t[0] = mod - 1;
    FOR(i, 1, w)
    {
        FOR(j, 1, m) if(((i >> a[j]) & 1) && ((i >> b[j]) & 1))
            {idp[i] = 1; break;}
        t[i] = i & 1 ? mod - t[i >> 1] : t[i >> 1];
    }
    f[0] = 1;
    FOR(i, 1, w) for(int j = i; j; j = i & (j - 1))
        if(!idp[j]) f[i] = add(f[i], mul(f[i ^ j], t[j]));
    printf("%d", mul(f[w], mul(m, 499122177)));
    return 0;
}
posted @ 2022-09-06 14:16  zuytong  阅读(38)  评论(0编辑  收藏  举报