烷基计数问题
题目描述:求每个节点儿子个数不超过 的 个点的无标号有根树的个数,对 取模。
数据范围:。
orz 王总
考虑 DP,设 表示 个节点时的答案。显然 。假设我们已经求出了 ,现在要求 。如果根节点的每个子树互不相同的话,那么显然有:
但由于节点是无标号的,因此考虑 引理。分三种情况讨论:
- 恒等置换,即 ,此时不动点数量就是上面的式子。
- 交换两个子树,即 ,此时不动点数量为 。
- 三个子树轮换,即 ,此时不动点数量为 。
综上,可得转移式:
直接计算时间复杂度 。若边算边处理 可将时间复杂度优化至 ,加上一些多项式科技后时间复杂度为 或 。
下面为 的代码:
#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;
}
题目描述:求每个点度数不超过 的 个点的无标号基环树个数,环长 ,对质数 取模。
数据范围:。
可以发现环上的点最多能连 个烷基(就是上面那题求的东西),于是设 表示一个环上的点向外连 个点的方案数。这里分两种情况讨论:
- 恒等置换,即 ,此时不动点数量为 。
- 交换两个烷基,即,此时不动点数量为 。
因此可得:
再考虑求总方案数。先枚举环长 。同样使用 引理,有两种类型的置换:
-
循环置换,即 ,此时循环节大小 ,个数 ,方案数为:
-
沿对称轴翻转的置换,即 ,再分两种情况讨论:
(1) ,此时有一半的情况每个点均有唯一一个与该点对称点,一半的情况有两个点的对称点是本身。此时方案数分别为:
(2) ,此时只有一个点的对称点是本身,此时方案数为:
因此, 就是把上面两种情况加起来除以 就行了。式子中的 可以 预处理。
总时间复杂度为 。
代码:
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现