SGU 282 Isomorphism
发布日期:2021-05-04 16:53:03 浏览次数:38 分类:原创文章

本文共 2331 字,大约阅读时间需要 7 分钟。

题目链接

思路

显然有 N! N ! 个边的置换,枚举边的置换肯定不可行。
因此,我们来考虑点置换和边置换的关系。
首先,考虑一条边 (x,y) ( x , y )

如果 x x y 在点置换中的同一循环节中,设这个循环节长度为 L L
L 为奇数,则 (x,y) ( x , y ) 所处边置换中循环节长度为 L L ,一共有 C L 2 条边,所以循环节的个数为 C2LL=L12 C L 2 L = L − 1 2 个。
L L 为偶数,则 ( x , y ) 所处边置换,出来上述长度为 L L 的情况,还有一种情况:
如果 x , y 在循环节中正好相距 L2 L 2 ,那么循环节长度为 L2 L 2 这样的循环节一共有 L2 L 2 个,循环节的个数为 C2LL2L+1=L2 C L 2 − L 2 L + 1 = L 2 个循环节。

再来考虑 x,y x , y 不在一个循环节的情况,设循环节长度分别为 L1,L2 L 1 , L 2
显然, (x,y) ( x , y ) 所在置换的循环节长度为 lcm(L1,L2) l c m ( L 1 , L 2 ) ,这样的循环节个数为 L1L2lcm(L1,L2)=gcd(L1,L2) L 1 L 2 l c m ( L 1 , L 2 ) = g c d ( L 1 , L 2 ) 个。

若一个点置换的循环节长度分别为 L1,L2,,LK L 1 , L 2 , ⋯ , L K ,那么边置换的循环节长度为:

c=i=1KLi2+i=1K1j=i+1Kgcd(Li,Lj) c = ∑ i = 1 K ⌊ L i 2 ⌋ + ∑ i = 1 K − 1 ∑ j = i + 1 K g c d ( L i , L j )

接下来我们求满足循环节长度为 L1,L2,,LK L 1 , L 2 , ⋯ , L K 的边置换个数。
这就相当于将 1N 1 ⋯ N 放入大小为 L1,L2,,LK L 1 , L 2 , ⋯ , L K 的环中,求总方案数。
显然,如 L L 不重复,那么总方案数为 N ! L 1 L 2 L K ,这里不给出证明了。
L L 有重复,假设 L 中有 t t 种不同的值,第 i 种值的个数为 ki k i ,那么总方案数(也就是满足条件的边置换个数)为:

S=N!L1L2LKk1!k2!kt! S = N ! L 1 L 2 ⋯ L K k 1 ! k 2 ! ⋯ k t !

最终的答案为:

Ans=1N!S×mc A n s = 1 N ! ∑ S × m c
其中 S,c S , c 如上所述。

代码

#include <cstdio>const int maxn=53;int fac[maxn+1],l[maxn+1],n,m,p,ans;int gcd(int x,int y){  return y?gcd(y,x%y):x;}inline int quickpow(int a,int b,int mo){  int res=1;  while(b)    {      if(b&1)        {          res=1ll*res*a%mo;        }      a=1ll*a*a%mo;      b>>=1;    }  return res;}inline int getans(int x){  int c=0,s=1,cnt=0;  for(register int i=1; i<=x; ++i)    {      c+=l[i]/2;      for(register int j=i+1; j<=x; ++j)        {          c+=gcd(l[i],l[j]);        }      s=(1ll*s*l[i])%p;      if(l[i]!=l[i-1])        {          s=(1ll*s*fac[cnt])%p;          cnt=0;        }      ++cnt;    }  s=(1ll*s*fac[cnt])%p;  s=(1ll*fac[n]*quickpow(s,p-2,p))%p;  ans=(1ll*ans+((1ll*s*quickpow(m,c,p))%p))%p;  return 0;}int search(int now,int lo,int hi){  if(!hi)    {      getans(now-1);    }  if(hi<lo)    {      return 0;    }  for(register int i=lo; i<=hi; ++i)    {      l[now]=i;      search(now+1,i,hi-i);      l[now]=0;    }  return 0;}int main(){  scanf("%d%d%d",&n,&m,&p);  fac[0]=1;  for(register int i=1; i<=n; ++i)    {      fac[i]=(1ll*fac[i-1]*i)%p;    }  search(1,1,n);  printf("%d\n",(int)((1ll*ans*quickpow(fac[n],p-2,p))%p));  return 0;}
上一篇:POJ 1721 CARDS
下一篇:BZOJ 1004 [HNOI2008]Cards

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2025年03月29日 08时07分10秒