【JZOJ 省選模擬】6702. 仙人掌(cactus)

代碼

Description

在這裏插入圖片描述
Input
在這裏插入圖片描述

Output

在這裏插入圖片描述
Sample Input
樣例 1 輸入
3 3
1 2
2 3
3 1

Sample Output
樣例 1 輸出
2

Data Constraint
在這裏插入圖片描述

Hint
樣例解釋
一共有 6 種排列:
在這裏插入圖片描述

思路

首先有貢獻的排列必須滿足每個點恰好屬於一個環(具體不太會證明)

一種分配方式的貢獻爲 2a ∗ (−1)b,a 爲長度 > 2 的環的數量(方向有 2 種)b 爲長度爲偶數的環的數量(交換行列式的兩列符號改變);

於是我們可以用圓方樹dp來求解分配價值
大概就是考慮當前點是否被分配的子樹價值

代碼

#include<bits/stdc++.h>
#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);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章