[ARC105F]Lights Out on Connected Graph
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ARC105F]Lights Out on Connected Graph相关的知识,希望对你有一定的参考价值。
Lights Out on Connected Graph
题解
对于边最后可以通过一系列操作变成红色的条件,我们可以理解成对节点进行染色。
由于所有边开始都是蓝色,最后都要变成红色,所以一条边的两个端点中有且只能有一个被染色。
由于合法的图是联通的,相当于存在能够覆盖在覆盖整个图的独立集。
首先看到
n
⩽
17
n\\leqslant 17
n⩽17,很明显的状压了,考虑怎么状压。
我们定义
d
p
S
dp_{S}
dpS表示点集
S
S
S所对应的子图合法的方案数。
很明显,对于一个连边状态固定的联通子图,我们对于点的染色状态只有两种,恰好对应两个可以覆盖全图的独立集,两者之间是互补的。
而对于一个合法子图,它一定是联通的,所以它的染色方案是固定的。
但对于一个染色方案固定的子图,它的连边方案却有很多种,我们设对于点集
S
S
S,它的点集
T
T
T是一种颜色,那么它的连边方案有
2
∣
E
(
S
)
−
E
(
T
)
−
E
(
S
−
T
)
∣
2^{|E(S)-E(T)-E(S-T)|}
2∣E(S)−E(T)−E(S−T)∣种,可以通过枚举子集的方法得到。
我们用
g
S
g_{S}
gS,表示点集为
S
S
S的子图的满足颜色条件的方案数。
容易得到转移方程式,
g
S
=
∑
T
∈
S
2
E
(
S
)
−
E
(
T
)
−
E
(
S
−
T
)
g_{S}=\\sum_{T\\in S}2^{E(S)-E(T)-E(S-T)}
gS=∑T∈S2E(S)−E(T)−E(S−T)
在这些连边方案中,有部分方案是不联通的,它们对应的染色方案自然也不是
2
2
2种,所以我们要先将这些方案去掉,再除以二,得到
d
p
S
dp_{S}
dpS。
由于这些方案是不连通的,所以我们自然也可以用枚举子集的方法得到答案。
设
h
S
h_{S}
hS表示点集为
S
S
S的子图的不满足连通性的子图数,容易得到状态转移方程式,
h
S
=
∑
T
⊂
S
2
d
p
T
h
S
−
T
h_{S}=\\sum_{T\\subset S}2dp_{T}h_{S-T}
hS=T⊂S∑2dpThS−T
但如果我们直接枚举所有子集,自然会因为不同连通块被枚举到的顺序问题产生重复,所以我们需要在枚举时保证连通块加入的顺序时固定的,如添加
l
o
w
b
i
t
(
T
)
=
l
o
w
b
i
t
(
S
)
lowbit(T)=lowbit(S)
lowbit(T)=lowbit(S)这样的条件。
很明显,
d
p
S
dp_{S}
dpS可以通过两者相减得到,
d
p
S
=
g
S
−
h
S
2
dp_{S}=\\frac{g_{S}-h_{S}}{2}
dpS=2gS−hS。
我们的答案即为
d
p
V
dp_{V}
dpV。
时间复杂度
O
(
3
n
)
O\\left(3^n\\right)
O(3n)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define MAXN (1<<17)+5
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int lim=15;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-7;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,dp[MAXN],g[MAXN],h[MAXN],sum[MAXN],pow2[505],hig[MAXN];
signed main(){
read(n);read(m);pow2[0]=h[0]=1;
for(int i=1;i<=m;i++){
int u,v;read(u);read(v);pow2[i]=add(pow2[i-1],pow2[i-1],mo);
for(int j=1;j<(1<<n);j++)if((j&(1<<u-1))&&(j&(1<<v-1)))sum[j]++;
}
for(int i=1;i<=n;i++)
for(int j=0;j<(1<<i-1);j++)hig[(1<<i-1)|j]=(1<<i-1);
for(int i=1;i<(1<<n);i++){
for(int j=i;j&hig[i];j=i&(j-1))g[i]=add(g[i],2ll*pow2[sum[i]-sum[j]-sum[i-j]]%mo,mo);
for(int j=i&(i-1);j&hig[i];j=i&(j-1))h[i]=add(h[i],1ll*dp[j]*h[i-j]%mo,mo);
dp[i]=add(g[i],mo-h[i],mo);h[i]=add(h[i],dp[i],mo);
}
printf("%d\\n",1ll*dp[(1<<n)-1]*inv2%mo);
return 0;
}
谢谢!!!
以上是关于[ARC105F]Lights Out on Connected Graph的主要内容,如果未能解决你的问题,请参考以下文章