[ABC213G] Connectivity 2

文章介绍了使用状压动态规划方法解决关于联通子图方案的问题,通过二进制状态表示和计算g、f数组来快速求解。通过枚举子图并考虑相关边的影响,给出了代码实现以解决给定图中特定节点k的方案数问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

幸亏状压DP的数据范围明显,不然自己估计想不出来

解法

先考虑答案如何计算,比如计算点 k k k的答案,可以枚举包含 1 , k 1,k 1,k 的联通子图,然后每一个联通子图的方案数乘上无关的边就行。
形式化地, 设 G G G 为全图的点集 , S S S G G G 的一个子图, f S f_{S} fS 表示 S S S 的联通子图的方案数, g S g_{S} gS 为S的子图数,那我们有:
a n s k = ∑ { 1 , k } ∈ S f S ∗ g ∁ G S ans_k=\sum_{\{1,k\}\in S} f_{S} *g_{\complement_{G}S } ansk={1,k}SfSgGS
考虑计算 f , g f,g f,g 由于点很少,我们用二进制数表示状态,用 状压 D P DP DP 解决
g g g 用点的个数就可以求, 2 c n t S 2^{cnt_S} 2cntS , c n t S cnt_S cntS S S S 的点数
f S = g S − ∑ 1 ∈ T ⊂ S f T ∗ g ∁ S T f_{S}=g_{S}-\sum_{1\in T\subset S} f_{T} *g_{\complement_{S}T} fS=gS1TSfTgST

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=(1<<17)+7,mod=998244353;
int n,m;
ll g[N],f[N],t[205];
vector<int> G[N];
void Get_g() {
    g[0]=1;
    for(int mask=1;mask<(1<<n);mask++) {
        ll tmp=0;
        for(int i=0;i<n;i++) if(mask>>i&1) {
            for(int j:G[i+1]) 
                if(mask>>(j-1)&1) tmp++;
        } g[mask]=t[(tmp>>1)];
    }
}
void Get_f() {
    for(int mask=1;mask<(1<<n);mask+=2) {
        for(int sub=mask;sub;sub=(sub-1)&mask) if(sub &1 ){
            f[mask]=(f[mask] + f[sub] * g[mask^sub] %mod) %mod;
        } 
        f[mask]=((g[mask]-f[mask])%mod+mod)%mod;
    }
}
int main() {
    scanf("%d%d",&n,&m);
    t[0]=1; for(int i=1;i<=200;i++) t[i]=(t[i-1]<<1)%mod;
    for(int i=1,u,v;i<=m;i++) {
        scanf("%d%d",&u,&v) ;
        G[u].push_back(v),G[v].push_back(u);
    }
    Get_g(),Get_f();
    for(int i=2;i<=n;i++) {
        ll tmp=0;
        for(int mask=1;mask<(1<<n);mask+=2) 
            if(mask>>(i-1)&1) tmp=(tmp+f[mask]*g[((1<<n)-1)^mask] %mod) %mod;
        printf("%lld\n",tmp);
    }
}

TXL

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值