[SHOI2006]有色图
感觉polya定理还没搞太清,写点东西助于理解.
首先注意到这题求的是本质不同的染色方案,这个好像很符合polya定理求的东西.
其中表示的是i置换下的循环节个数
要用这个定理首先必须要找置换.发现边的置换很难找,于是考虑寻找点的置换和边的置换的联系.
如果我们暴力枚举点的置换.再把置换写成循环的形式,这样这些点就被我们分成一组一组的了.每个组就是一个循环.
一条边是连在两个点之间的,我们再来考虑在点的置换确定的条件下,边的置换个数的循环个数.
这个个数怎么求呢?
分两种情况讨论:
case1 两个点在一个循环内
现在想象l个点它们围成一个环,它们之间连满了边,边数是,如果环的元素是奇数个的话,你转l次就可以转回原来的样子,点一一对应,边也一一对应.那么边的循环长度显然就为l了,然后又有条边,那么循环节个数就是了.
如果l为偶数,那么就会有一些边,你转180度,就可以转回来,它们的循环长度为.
这些边有多少个呢?显然是个,我们愉快地减掉它,就好了.循环个数:
case2 两个点在不同循环内
同样用上面的方法,根据循环长度,计算循环个数,假设这两个点所在的点循环的长度分别为.那么它们合成的循环长度就为,然后边数显然为这就很美滋滋了.循环个数就为
所以这样以来,已知点的置换,得到的边置换的循环个数就为:
但是这样显然是不行的.
很容易发现对称群个数这个显然是不可以接受的.那我们想办法简化状态,之前的状态里包含了每个循环里具体有哪些点的信息,但是这些信息是多余的,我们只要知道每个循环里有多少个元素就可以了,那么我们原来枚举的东西,就可以代替成枚举整数的拆分.
但是光知道一种状态下的答案是不够的,我们还得计算有多少种点的置换对应这种状态.
设被当前状态为:被分成了k个循环,每个循环的元素个数为.
我们算的是状态对应的点的置换数,想一想发现,一个循环里点的顺序不同代表的置换是不同的,如果固定第一个点的话,后面的不同排列个数为
所以如果每个l都不相同的话,那么
如果有相同的,那么设为第i种l的个数.
所以$$S=\frac{n!}{(\prod_{i=1}kl_i)*(\prod_{i=1}q_i)}$$
这里可以用费马小定理求逆元.
// luogu-judger-enable-o2
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define maxn 105
#define ll long long
using namespace std;
ll mod,f[maxn],ans;
int n,m,rec[maxn];
ll gcd(ll a,ll b)
{
if(b==0)return a;
return gcd(b,a%b);
}
ll ksm(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1)res=(res*a)%mod;
a=a*a%mod;b>>=1;
}
return res;
}
void calc(int x)
{
ll sum=0,mul=1;int now=1;
for(int i=1;i<=x;i++)sum+=rec[i]/2;
for(int i=1;i<=x;i++)
for(int j=i+1;j<=x;j++)sum+=gcd(rec[i],rec[j]);
for(int i=1;i<=x;i++)(mul*=rec[i])%=mod;
for(int i=2;i<=x;i++)
{
if(rec[i]!=rec[i-1])
mul=mul*f[now]%mod,now=0;
now++;
}
mul=mul*f[now]%mod;
mul=f[n]*ksm(mul,mod-2)%mod;
//cout<<n<<" "<<mul<<endl;
ans=(ans+mul*ksm(m,sum)%mod)%mod;
}
void dfs(int k,int x,int s)
{
if(!x)calc(k-1);
if(x<s)return;
for(int i=s;i<=x;i++)
{
rec[k]=i;
dfs(k+1,x-i,i);
}
}
int main()
{
cin>>n>>m>>mod;f[0]=1;
for(int i=1;i<=n;i++)f[i]=f[i-1]*i%mod;
dfs(1,n,1);ans=ans*ksm(f[n],mod-2)%mod;
printf("%lld",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话