【JZOJ 省选模拟】6702. 仙人掌(cactus)

代码

Description

【JZOJ 省选模拟】6702. 仙人掌(cactus)_第1张图片
Input
【JZOJ 省选模拟】6702. 仙人掌(cactus)_第2张图片

Output

在这里插入图片描述
Sample Input
样例 1 输入
3 3
1 2
2 3
3 1

Sample Output
样例 1 输出
2

Data Constraint
【JZOJ 省选模拟】6702. 仙人掌(cactus)_第3张图片

Hint
样例解释
一共有 6 种排列:
【JZOJ 省选模拟】6702. 仙人掌(cactus)_第4张图片

思路

首先有贡献的排列必须满足每个点恰好属于一个环(具体不太会证明)

一种分配方式的贡献为 2a ∗ (−1)b,a 为长度 > 2 的环的数量(方向有 2 种)b 为长度为偶数的环的数量(交换行列式的两列符号改变);

于是我们可以用圆方树dp来求解分配价值
大概就是考虑当前点是否被分配的子树价值

代码

#include
#define ll long long 
using namespace std;
const int N=2e5+77,M=N*2,mod=998244353;
int n,m,du[N],cnt,e[M],nx[M],ls[N],Cnt,E[M],next[M],Ls[M];
void add(int x,int y)
{
	cnt++; e[cnt]=y; nx[cnt]=ls[x]; ls[x]=cnt;
	cnt++; e[cnt]=x; nx[cnt]=ls[y]; ls[y]=cnt;
}

void Add(int x,int y)
{
	Cnt++; E[Cnt]=y; next[Cnt]=Ls[x]; Ls[x]=Cnt;
	Cnt++; E[Cnt]=x; next[Cnt]=Ls[y]; Ls[y]=Cnt;
}

int tot,dfn[N],low[N],d[N],bz[M],nn;
void tarjan(int x)
{
	dfn[x]=low[x]=++tot,d[++d[0]]=x;
	for(int i=ls[x]; i; i=nx[i]) if(!bz[i])
	{
		bz[i]=bz[i^1]=1;
		if(!dfn[e[i]])
		{
			tarjan(e[i]),low[x]=min(low[x],low[e[i]]);
			if(low[e[i]]>=dfn[x])
			{
				nn++;
				while(1)
				{
					Add(nn,d[d[0]]),d[0]--,du[nn]++;
					if(d[d[0]+1]==e[i]) break;
				}
				Add(nn,x),du[nn]++;
			}
		} else low[x]=min(low[x],dfn[e[i]]);
	}
}

ll f[N][2],g[N][2];
void solve(int x,int p)
{
	if(x<=n) 
	{
		f[x][0]=1;
		for(int i=Ls[x]; i; i=next[i]) if(E[i]!=p)
		{
			solve(E[i],x);
			f[x][1]=(f[x][1]*f[E[i]][0]+f[x][0]*f[E[i]][1])%mod;
			f[x][0]=f[x][0]*f[E[i]][0]%mod;
		}
	} 
	else 
	{
		for(int i=Ls[x]; i; i=next[i]) if(E[i]!=p) solve(E[i],x);
		d[0]=0; 
		for(int i=Ls[x]; i; i=next[i]) if(E[i]!=p) d[++d[0]]=E[i];
		if(d[0]==1) 
		{
			f[x][0]=f[d[1]][1],f[x][1]=-f[d[1]][0];
			return;
		}
		ll sum=1; for(int i=1; i<=d[0]; i++) sum=sum*f[d[i]][0]%mod;
		g[0][0]=1,g[1][0]=f[d[1]][1],g[1][1]=-f[d[1]][0];
		for(int i=2; i<=d[0]; i++) 
		{
			g[i][0]=(f[d[i]][1]*g[i-1][0]-f[d[i]][0]*f[d[i-1]][0]%mod*g[i-2][0])%mod;
			g[i][1]=(f[d[i]][1]*g[i-1][1]-f[d[i]][0]*f[d[i-1]][0]%mod*g[i-2][1])%mod;
		}
		f[x][1]=(sum*2*((d[0]&1)?-1:1)+g[d[0]][1]-g[d[0]-1][0]*f[d[d[0]]][0])%mod;
		f[x][0]=g[d[0]][0];
	}
}

int main()
{
	freopen("cactus.in","r",stdin); freopen("cactus.out","w",stdout);
	scanf("%d%d",&n,&m);
	cnt=1,nn=n;
	for(int i=1,x,y; i<=m; i++) scanf("%d%d",&x,&y),add(x,y);
	tarjan(1);
	solve(1,0);
	printf("%lld",(f[1][1]+mod)%mod);
}

你可能感兴趣的:(【JZOJ 省选模拟】6702. 仙人掌(cactus))