首页 > 其他分享 >[ABC253Ex] We Love Forest

[ABC253Ex] We Love Forest

时间:2023-01-07 16:15:20浏览次数:58  
标签:cnt Love int cnte ret times ABC253Ex Forest oplus

[ABC253Ex] We Love Forest Solution

目录

更好的阅读体验戳此进入

题面

给定 $ n $ 个点无边的图,给定 $ m $ 条待选的无向边。每次等概率地从 $ m $ 条边中抽取一条边加入图中。 $ n - 1 $ 次询问求加 $ 1, 2, \cdots, n - 1 $ 次边后原图形成一个森林(一棵树亦为森林)的概率为多少。对 $ 998244353 $ 取模。

Solution

考虑 FZT,即子集计数,具体可参考 FZT - 子集计数学习笔记[ABC213G] Connectivity 2 Solution,发现本题与 ABC213G 相似。

因为本题存在选的边数的限制,所以不难想到需要在一般 FZT 的状态中额外添加一维记录。

状态类比 ABC213G,较为显然,令 $ F(i, S) $ 表示选了 $ i $ 条边,点集状态为 $ S $ 形成的森林数。令 $ G(S) $ 表示点集状态为 $ S $ 生成树的总方案数。

首先考虑如何处理 $ G(S) $,发现这个东西就是个裸的矩阵树定理。不过也可以通过枚举子集设计转移来实现,令 $ cnt(S, T) $ 表示点集 $ S $ 和点集 $ T $ 之间的边数,方程不难想到为:

\[G(S) = \sum_{T \subsetneq S}G(T) \times G(S \oplus T) \times cnt(T, S \oplus T) \]

然后发现这个东西有重复,不难想到重复分为两种,一种是因为 $ T $ 和 $ S \oplus T $ 对调之后属于相同方案而被重复统计了,这个可以通过钦定一个点解决,或者在最终答案乘一个 $ \dfrac{1}{2} $ 解决。另一种是因为我们的转移,是通过将两个树形结构通过之间的边拼接在一起来实现的,而这种情况也可以认为是将一棵完整的树通过断开某一条边然后分别计算子树,这样的话对于一棵确定的树断开每条边都是等价的,所以会重复边数次,也就是答案需要乘一个 $ \dfrac{1}{\lvert S \rvert - 1} $,故可以考虑将转移改为:

\[G(S) = \dfrac{1}{2(\lvert S \rvert - 1)} \sum_{T \subsetneq S}G(T) \times G(S \oplus T) \times cnt(T, S \oplus T) \]

或:

\[G(S) = \dfrac{1}{\lvert S \rvert - 1} \sum_{\operatorname{lowbit}(S) \in T \subsetneq S}G(T) \times G(S \oplus T) \times cnt(T, S \oplus T) \]

然后初始值大概是 $ G(2^k) = 1 $。

不难发现如果无脑处理 $ cnt $ 的话复杂度是 $ O(2^{2n}m) $,显然寄,于是考虑优化,令 $ cnte(S) $ 表示点集 $ S $ 中的边数,不难想到对于 $ cnt $ 可以如下容斥:

\[cnt(S, T) = cnte(S \vee T) - cnte(S) - cnte(T) \]

则预处理 $ cnte $ 的复杂度为 $ O(m2^n) \(,\) cnt $ 可以 $ O(1) $ 求解,$ G $ 的处理则是 $ O(3^n) $ 的。

然后矩阵树定理的结论大概就是首先对这个图建出拉普拉斯矩阵 $ L $,然后答案就是 $ \det(L_0) $,其中 $ L_0 $ 表示 $ L $ 去掉第 $ i $ 行第 $ i $ 列的子矩阵,其中 $ i $ 任意。具体证明参考 矩阵树定理(Matrix-tree Theorem)笔记。所以只需要矩阵建出来无脑求一下行列式即可。

于是考虑如何转移 $ F $,依然类比 ABC213G,我们令 $ \lvert S \rvert $ 表示点集 $ S $ 中点的数量,也就是 __builtin_popcount(S),不难发现转移:

\[F(i, S) = \sum_{1 \in T \subsetneq S} G(T) \times F(i - (\lvert T \rvert - 1), S \oplus T) \]

也就是钦定一个子集为一棵树,然后剩下的作为森林,钦定 $ 1 $ 节点在树中可以去重,具体在 ABC213G 也有说明。

不过很遗憾这个又是错的。我们在 ABC213G 中钦定 $ 1 $ 是因为 $ 1 $ 一定被选,但是在本题里并没有这个限制,所以我们要换一种写法,不难想到使用 $ S $ 中的最后一个 $ 1 $ 是易于实现且正确的,即 $ \operatorname{lowbit}(S) $,或者说 $ S \land -S $。于是转移改为:

\[F(i, S) = \sum_{\operatorname{lowbit}(S) \in T \subsetneq S} G(T) \times F(i - (\lvert T \rvert - 1), S \oplus T) \]

边界条件的话就是如果 $ S $ 的点数恰好为 $ i + 1 $,那么显然就是一棵树,即 $ F(i, S) = G(S) $。

然后考虑答案,令 $ Smx = 2^n - 1 $,即全集,不难想到对于选 $ i $ 条边的答案 $ ans_i $ 有:

\[ans_i = \dfrac{F(i, Smx) \times i!}{m^i} \bmod{998244353} \]

也不难理解,概率转计数,总方案数为 $ m_i $,然后要让所有点形成森林,方案中选择的 $ i $ 条边任意排列均不同,所以需要在乘一个 $ i! $。

大概就这样了,处理 $ G $ 的复杂度为 $ O(n^3 2^n) $,处理 $ F $ 的复杂度为 $ O(n 3^n) $,处理答案复杂度作为常数,最终复杂度 $ O((m + n^3) 2^n + 3^n) $,可以通过。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

#define MAX_STATUS (20000)
#define MOD (ll)(998244353)
#define EXIST(x) (S & (1 << ((x) - 1)))

template < typename T = int >
inline T read(void);

struct Edge{
    Edge* nxt;
    int to;
    OPNEW;
}ed[1100];
ROPNEW(ed);
Edge* head[20];

int N, M;
int deg[20];
ll G[MAX_STATUS], F[20][MAX_STATUS];
int cnte[MAX_STATUS];
ll fact[30];

int lowbit(int x){return x & -x;}
int CalCnt(int S, int T){return cnte[S | T] - cnte[S] - cnte[T];}
ll qpow(ll a, ll b){
    ll ret(1), mul(a);
    while(b){
        if(b & 1)ret = ret * mul % MOD;
        b >>= 1;
        mul = mul * mul % MOD;
    }return ret;
}

int main(){fact[0] = 1;
    for(int i = 1; i <= 20; ++i)fact[i] = fact[i - 1] * i % MOD;
    N = read(), M = read();
    const int Smx = (1 << N) - 1;
    for(int i = 1; i <= M; ++i){
        int s = read(), t = read();
        head[s] = new Edge{head[s], t};
        head[t] = new Edge{head[t], s};
    }
    for(int S = Smx; S; S = (S - 1) & Smx){
        int cnt(0);
        for(int p = 1; p <= N; ++p)
            for(auto i = head[p]; i; i = i->nxt)
                if(EXIST(p) && EXIST(SON))++cnt;
        cnt >>= 1;
        cnte[S] = cnt;
    }
    for(int S = 1; S <= Smx; ++S){
        if(__builtin_popcount(S) == 1){G[S] = 1; continue;}
        for(int T = (S - 1) & S; T; T = (T - 1) & S)
            if(T & lowbit(S))
                (G[S] += G[T] * G[S ^ T] % MOD * CalCnt(T, S ^ T) % MOD) %= MOD;
        (G[S] *= qpow(__builtin_popcount(S) - 1, MOD - 2)) %= MOD;
    }
    for(int i = 0; i <= N - 1; ++i)
        for(int S = 0; S <= Smx; ++S){
            if(__builtin_popcount(S) == i + 1){F[i][S] = G[S]; continue;}
            for(int T = (S - 1) & S; T; T = (T - 1) & S)
                if(T & lowbit(S) && i - (__builtin_popcount(T) - 1) >= 0)
                    (F[i][S] += G[T] * F[i - (__builtin_popcount(T) - 1)][S ^ T]) %= MOD;
        }
    for(int i = 1; i <= N - 1; ++i)
        printf("%lld\n", F[i][Smx] * fact[i] % MOD * qpow(qpow(M, i), MOD - 2) % MOD);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2022_12_07 初稿

标签:cnt,Love,int,cnte,ret,times,ABC253Ex,Forest,oplus
From: https://www.cnblogs.com/tsawke/p/17032823.html

相关文章

  • NC22600 Rinne Loves Dynamic Graph
    题目链接题目题目描述Rinne学到了一个新的奇妙的东西叫做动态图,这里的动态图的定义是边权可以随着操作而变动的图。当我们在这个图上经过一条边的时候,这个图上所有边......
  • NC22594 Rinne Loves Graph
    题目链接题目题目描述Island发生了一场暴乱!现在Rinne要和Setsuna立马到地上世界去。众所周知:Island是有一些奇怪的城镇和道路构成的(题目需要,游戏党勿喷),有些城镇......
  • R语言随机森林RandomForest、逻辑回归Logisitc预测心脏病数据和可视化分析|附代码数据
    全文链接:http://tecdat.cn/?p=22596最近我们被客户要求撰写关于预测心脏病数据的研究报告,包括一些图形和统计输出。本报告是对心脏研究的机器学习/数据科学调查分析。更......
  • k8s域名解析错误:pod中/etc/reslove.conf中nameserver和kube-dns中ip不一致
    问题:k8s集群中,某台node节点上,dns解析失败,进入pod中查看/etc/reslove.conf中nameserver和kube-dns不一致,如图: pod中如下:   kube-dns如下:   造成这种......
  • Isolation forest阅读笔记
    IForest所基于的假设异常是由较少实例组成的少数派它们拥有与正常实例差别较大的属性换句话说,异常是少而不同的(fewanddifferent),这使得它们比正常的点更容易被孤立......
  • KingbaseES V8R3集群运维案例之---failover故障处理
    ​案例说明:此案例,为KingbaseESV8R3集群failover切换时,通用的故障处理方式。通过对failover.log和recovery.log日志的解读,让大家了解KingbaseESV8R3集群failover的恢复......
  • P3599 Koishi Loves Construction
    \(\mathcalLink\)首先考虑任务一。注意到前缀和互不相同\(\iff\)不存在一段区间\([l,r](l>1)\),使其和为\(0\)。因此,\(n\)应当放在第一个。考虑到剩余数总和为\(......
  • [BUUCTF][Web][极客大挑战 2019]LoveSQL 1
    打开靶机url,页面显示有两个输入框,框中输入123',发现两个框都有sql注入问题爆出一下错误YouhaveanerrorinyourSQLsyntax;checkthemanualthatcorrespondstoy......
  • Forest + IDEA = 双倍快乐!ForestX 隆重登场
    Forest+IDEA=双倍快乐!ForestX隆重登场Forest是一款声明式的Java开源HTTP框架,相比它的前辈Httpclient和OkHttp更简明易懂、也更容易维护废话不多说,先让我......
  • Clover引导都支持哪些.efi文件
    接下来给大家介绍EFI/Clover/drivers/UEFI目录下可能会用到的一些​​.efi​​文件:1.AptioInputFix.efi「为使用AMIUEFIBIOS的主板提供FileVault2键盘驱动」2.ApfsDrive......