20200504 zr T1【映射樹與原樹重合的樹個數】

題目描述:

給定一個11nn的的排列p1,p2,,pnp_1,p_2,…,p_n,問有多少個不同的有標號無根樹,滿足如果iijj有邊那麼pip_ipjp_j之間也有邊,對998244353998244353取模。

n500000n\le500000

題目分析:

首先將排列拆成一個個的置換環。
考慮兩個循環之間的連邊,由題,如果xxyy連邊,那麼xx在環上的下一個點也要向yy在環上的下一個點連邊。
稍加思考可以發現:

  • 長度爲xx的環向長度爲yy的環連邊,(假設x<yx<y),那麼一定滿足xyx|y,否則就會連出環。(考慮xx的第11個點和第y%x+1y\%x+1個點,它們都向yy的第1個點和第xx點連邊)
  • 兩個環之間只能連最多1條邊,方案數爲xx
  • 長度大於3的環內不能連邊(如果環長爲奇數會成環,如果環長爲偶數當與更小的環連邊時會連出環)
  • 要形成一棵樹,必須至少有1個長度2\le2的環。(長度爲2的環可以環內連邊形成一個連通塊,長度爲1的環可以將所有連通塊連通。)
  • 樹的生成方式一定是形如最小的環爲根,然後按照大小依次將環掛在樹上。(大環同時接兩個小環會連出環)
    (PS:上面所說的連出環是指連的邊形成了環)

於是我們依次考慮每種大小的循環:

假設現在有pp個長度爲mm的循環,那麼一定是這pp個循環先連成k[1,p]k\in[1,p]個連通分量,然後每個連通分量裏有一個循環向更小的循環連邊。
枚舉kk

  • kk個連通分量向更小的循環連邊的方案數是(dmcntd)k(\sum_{d|m}cnt_d)^k,其中cntdcnt_d表示在長度爲dd的循環裏面的點的個數。
  • 每個連通分量內部連邊,一條邊有mm種連法,總共p1(k1)p-1-(k-1)條邊,方案數爲mpkm^{p-k}
  • 最後的問題就是pp個點連成kk個連通分量的方案數,這可以看做加了一個虛點,強制它的度數爲kk(這樣它的兒子就是k個連通分量),用prufer序列計算,在p1p-1個位置中出現k1k-1次,其餘位置隨便填,方案數爲(p1k1)ppk\binom {p-1}{k-1}p^{p-k}
  • 所以總的方案數就是k=1p(p1k1)ppkmk(dmcntd)k\sum_{k=1}^p\binom {p-1}{k-1}p^{p-k}m^k(\sum_{d|m}cnt_d)^k
  • w=dmcntdw=\sum_{d|m}cnt_d,則上式可以化爲 w(mw+p)p1w(mw+p)^{p-1}

如果有長度爲1的循環肯定2要向1連,如果沒有的話就要選一個2的循環內部連邊使圖形成一棵樹。

Code:

#include<bits/stdc++.h>
#define maxn 500005
using namespace std;
const int mod = 998244353;
int T,n,p[maxn],cnt[maxn],f[maxn];
bool vis[maxn];
inline int Pow(int a,int b){
	int s=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
	return s;
}
int main()
{
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&p[i]),cnt[i]=f[i]=vis[i]=0;
		for(int i=1;i<=n;i++) if(!vis[i]){
			int len=1;
			for(int j=p[i];j!=i;j=p[j]) vis[j]=1,len++;
			cnt[len]++;
		}
		for(int i=1;i<=n;i++)
			for(int j=i+i;j<=n;j+=i)
				f[j]+=cnt[i]*i;
		int ans=0;
		if(cnt[1]){
			ans=cnt[1]>1?Pow(cnt[1],cnt[1]-2):1;
			for(int i=2;i<=n;i++) if(cnt[i]) ans=1ll*ans*f[i]%mod*Pow(cnt[i]*i+f[i],cnt[i]-1)%mod;
		}
		else if(cnt[2]){
			ans=Pow(2*cnt[2],cnt[2]-1);
			for(int i=3;i<=n;i++) if(cnt[i]) ans=1ll*ans*f[i]%mod*Pow(cnt[i]*i+f[i],cnt[i]-1)%mod;
		}
		printf("%d\n",ans);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章