BZOJ 1488: [HNOI2009]图的同构 polay

题意:两个图AB同构:把A的顶点重新编号后与B一模一样。求n个顶点的图一共有多少个?(同构的算一种)

思路:边有n*(n-1)/2,这些边可以有可以没有,所以等同于边的颜色有两种。然后将n划分成循环节的和,n=L1+L2+……+Lm。现在需要把点置换映射到边置换。两个边在一个点循环节(大小L)时边置换循环节为L/2,否则为Gcd(L1,L2)。然后就是计算(L1,L2,……,Lm)这种划分的个数,设m个循环有t种数字,每种数字个数p1,p2,……,pt,那么划分个数为:n!/(L1*L2……*Lm*p1!*……*pt!)。

 

const int mod=997;
 
int p[N];
int n;
int f[N][2],cnt;
 
void init()
{
    p[0]=1;
    int i;
    for(i=1;i<N;i++) p[i]=p[i-1]*i%mod;
}
 
int ans;
 
 
void cal()
{
    i64 x=0,i,j;
    FOR0(i,cnt)
    {
        x+=f[i][0]/2*f[i][1]+(f[i][1]-1)*f[i][1]/2*f[i][0];
        for(j=i+1;j<cnt;j++) x+=f[i][1]*f[j][1]*Gcd(f[i][0],f[j][0]);
    }
    i64 pp=1;
    FOR0(i,cnt) pp=pp*myPow(f[i][0],f[i][1],mod)%mod*p[f[i][1]]%mod;
    pp=p[n]*gcdReverse(pp,mod)%mod;
 
    ans+=myPow(2,x,mod)*pp%mod;
    ans%=mod;
}
 
void DFS(int t,int re)
{
    if(re==0)
    {
        cal();
        return;
    }
    if(t>re) return;
    DFS(t+1,re);
    int i;
    for(i=1;i*t<=re;i++)
    {
        f[cnt][0]=t;
        f[cnt++][1]=i;
        DFS(t+1,re-i*t);
        cnt--;
    }
}
 
int main()
{
    init();
    RD(n);
    DFS(1,n);
    ans=ans*gcdReverse(p[n],mod)%mod;
    PR(ans);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值