烷基计数问题

烷基计数加强加强版

题目描述:求每个节点儿子个数不超过 3n 个点的无标号有根树的个数,对 998244353 取模。

数据范围:1n105


orz 王总

考虑 DP,设 fn 表示 n 个节点时的答案。显然 f0=1。假设我们已经求出了 f1,f2,,fn1,现在要求 fn。如果根节点的每个子树互不相同的话,那么显然有:

fn=i+j+k=n1fifjfk

但由于节点是无标号的,因此考虑 Burnside 引理。分三种情况讨论:

  1. 恒等置换,即 (123123),此时不动点数量就是上面的式子。
  2. 交换两个子树,即 (123213)(123132)(123321),此时不动点数量为 2i+j=n1fifj
  3. 三个子树轮换,即 (123231)(123312),此时不动点数量为 3i=n1fi

综上,可得转移式:

fn=16(i+j+k=n1fifjfk+32i+j=n1fifj+23i=n1fi)

直接计算时间复杂度 O(n3)。若边算边处理 gn=i+j=nfifj 可将时间复杂度优化至 O(n2),加上一些多项式科技后时间复杂度为 O(nlog2n)O(nlogn)

下面为 O(n2) 的代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){
	int f=1,r=0;char c=getchar();
	while(!isdigit(c))f^=c=='-',c=getchar();
	while(isdigit(c))r=(r<<1)+(r<<3)+(c&15),c=getchar();
	return f?r:-r;
}
const int N=5007,mod=998244353,inv6=166374059;
inline void inc(int &x,int y){x+=y-mod,x+=x>>31&mod;}
int n,f[N],g[N];
int main(){
#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
#endif
	n=read(),f[0]=1;
	for(int i=0;i<n;i++){
		for(int j=0;j<=i;j++)
			g[i]=(g[i]+(ll)f[j]*f[i-j])%mod;
		int res=0;
		for(int j=0;j<=i;j++)
			res=(res+(ll)g[j]*f[i-j])%mod;
		inc(f[i+1],res),res=0;
		for(int j=0;2*j<=i;j++)
			res=(res+(ll)f[j]*f[i-2*j])%mod;
		inc(f[i+1],3ll*res%mod);
		if(i%3==0)inc(f[i+1],2ll*f[i/3]%mod);
		f[i+1]=(ll)f[i+1]*inv6%mod;
	}
	printf("%d\n",f[n]);
	return 0;
}

[JSOI2011]同分异构体计数

题目描述:求每个点度数不超过 4n 个点的无标号基环树个数,环长 [3,m],对质数 p 取模。

数据范围:1n1000,1m50,mn,104p2×109


可以发现环上的点最多能连 2 个烷基(就是上面那题求的东西),于是设 gn 表示一个环上的点向外连 n1 个点的方案数。这里分两种情况讨论:

  1. 恒等置换,即 (1212),此时不动点数量为 i+j=n1fifj
  2. 交换两个烷基,即(1221),此时不动点数量为 2i=n1fi

因此可得:

gn=12(i+j=n1fifj+2i=n1fi)

再考虑求总方案数。先枚举环长 k[3,m]。同样使用 Burnside 引理,有两种类型的置换:

  1. 循环置换,即 pi=(pi+a)modk (a[0,k) ),此时循环节大小 s=gcd(a,k),个数 t=ks,方案数为:

    ti=1sbi=ni=1sgbi

  2. 沿对称轴翻转的置换,即 pi=(api)modk (a[0,k) ),再分两种情况讨论:

    (1) k0(mod2),此时有一半的情况每个点均有唯一一个与该点对称点,一半的情况有两个点的对称点是本身。此时方案数分别为:

    2i=1k/2bi=ni=1k/2gbi,b0+b1+2i=2k/2bi=ni=0k/2gbi

    (2) k1(mod2),此时只有一个点的对称点是本身,此时方案数为:

    b0+2i=1k/2bi=ni=0k/2gbi

因此,ansk 就是把上面两种情况加起来除以 2k 就行了。式子中的 i=1mbi=ni=1mgbi 可以 O(n2m) 预处理。

总时间复杂度为 O(n2m+m2logm)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){
	int f=1,r=0;char c=getchar();
	while(!isdigit(c))f^=c=='-',c=getchar();
	while(isdigit(c))r=(r<<1)+(r<<3)+(c&15),c=getchar();
	return f?r:-r;
}
const int N=1007,M=57;
int inv2,inv6,mod;
int gcd(int x,int y){return y?gcd(y,x%y):x;}
inline void inc(int &x,int y){x+=y-mod,x+=x>>31&mod;}
inline void dec(int &x,int y){x-=y,x+=x>>31&mod;}
inline int qpow(int a,int b){
	int res=1;
	for(;b;b>>=1,a=(ll)a*a%mod)
		if(b&1)res=1ll*res*a%mod;
	return res;
}
int n,m,f[N],g[N],h[M][N];
inline void init(){
	inv2=qpow(2,mod-2),inv6=qpow(6,mod-2),f[0]=1;
	for(int i=0;i<n;i++){
		for(int j=0;j<=i;j++)
			g[i]=(g[i]+(ll)f[j]*f[i-j])%mod;
		int res=0;
		for(int j=0;j<=i;j++)
			res=(res+(ll)g[j]*f[i-j])%mod;
		inc(f[i+1],res),res=0;
		for(int j=0;2*j<=i;j++)
			res=(res+(ll)f[j]*f[i-2*j])%mod;
		inc(f[i+1],3ll*res%mod);
		if(i%3==0)inc(f[i+1],2ll*f[i/3]%mod);
		f[i+1]=(ll)f[i+1]*inv6%mod;
	}
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
#endif
	n=read(),m=read(),mod=read(),init(),g[0]=0;
	for(int i=1;i<=n;i++){
		g[i]=i&1?f[i/2]:0;
		for(int j=0;j<i;j++)
			g[i]=(g[i]+(ll)f[j]*f[i-j-1])%mod;
		g[i]=(ll)g[i]*inv2%mod;
	}
	h[0][0]=1;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			for(int k=0;k<j;k++)
				h[i][j]=(h[i][j]+(ll)h[i-1][k]*g[j-k])%mod;
	int ans=0;
	for(int k=3;k<=m;k++){
		int res=0;
		for(int a=0;a<k;a++){
			int s=gcd(a,k),t=k/s;
			if(n%t==0)inc(res,h[s][n/t]);
		}
		if(k&1){
			int tmp=0;
			for(int i=1;i<=n-k+1;i++)
				if((n-i)%2==0)inc(tmp,(ll)g[i]*h[k>>1][(n-i)>>1]%mod);
			inc(res,(ll)k*tmp%mod);
		}else{
			if(n%2==0)inc(res,(ll)(k>>1)*h[k>>1][n>>1]%mod);
			int tmp=0;
			for(int i=1;i<=n-k+1;i++)
				for(int j=1;i+j<=n-k+2;j++)
					if((n-i-j)%2==0)inc(tmp,(ll)g[i]*g[j]%mod*h[k/2-1][(n-i-j)>>1]%mod);
			inc(res,(ll)k/2*tmp%mod);
		}
		ans=(ans+(ll)res*qpow(k<<1,mod-2))%mod;
	}
	printf("%d\n",ans);
	return 0;
}
posted @   b1ts  阅读(189)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示