烷基计数 题解
好怪的化学题……
题意:
loj上这个有三版,普通版
首先说一下:
- 普通版
我们设
那么我们前面那个组合数有什么用呢?我们发现这三棵子树的点数可能是相等的,但是由于是无标号计数,当两个是相同情况的时候如果直接乘会重复计算。于是我们就需要前面那个组合数来统计答案。
inline int C(int n,int m){
if(m==1)return n;
if(m==2)return 1ll*(n+1)*n/2;
if(m==3){
return n*n+n*(n-1)*(n-2)*inv6;//inv6是6的逆元
}
return 0;//看不懂就把组合数拆开 还有这题有点卡常少取点模
}
for(int i=1;i<=n;i++){
for(int j=0;j<=i;j++){
for(int k=j;j+k<=i;k++){
int l=i-(j+k);
if(l<k)continue;//防止计重
if(j==k&&k==l)dp[i]+=C(dp[j],3);//均省略取模以增加可读性
else if(j==k)dp[i]+=C(dp[j],2)*dp[l];
else if(k==l)dp[i]+=C(dp[k],2)*dp[j];
else dp[i]+=dp[j]*dp[k]*dp[l];
}
}
}
- 加强版
首先显然我们之前枚举了太多我们用不到的选项和重复选项。而且重复这块很致命。考虑改变状态设计。
设
int main(){
scanf("%d",&n);
dp[1][0]=1;
for(int i=1;i<n;i++){//子树大小 显然不能到n
for(int j=n;j>i;j--){//父亲大小 显然最小不能到i
for(int k=1;k<=3;k++){//有几棵子树
for(int l=1;l<=k&&l*i<j;l++){//有几棵和i长的一样的子树
dp[j][k]=dp[j][k]+1ll*C(dp[i][0]+dp[i][1]+dp[i][2],l)*dp[j-i*l][k-l];
}
}
}
}
printf("%d",dp[n][4]);
}
- 加强版加强版
Polya定理。先咕着。不知道什么时候能补。也许AFO了都补不上。
首先既然要Polya定理那就先找置换。发现因为有
首先设答案的生成函数为
对于置换
对于置换
剩下的置换是三元环,也就是
于是按照polya定理的柿子写出来搞个生成函数形式,就变成了这个诡异的方程:
我管你会不会解反正我不会解
好了以上是三个月前naive的我(虽然现在也一样naive)的吐槽。我们其实可以把上边那个
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现