【HNOI2009】bzoj1488 图的同构

本文探讨了在完全图上对边进行黑白染色的问题,通过将置换问题转化为图论中的边循环计数问题,利用组合数学的方法进行高效求解。文章详细介绍了如何通过枚举正整数拆分并计算不同长度循环的数量来简化复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先可以把问题转化成在完全图上对边进行黑白染色。
对于每个点的置换,要求出有多少关于边的不动点。把置换分解成循环,可以发现,一个长度为x的点的循环内部有x2个边的循环,两个长度为xy的点的循环之间有gcd(x,y)个边的循环,这样关于边的不动点总数就是2m,其中m表示边的循环的总数。
但是直接枚举点的置换有n!种,显然无法承受。因为每种置换对答案的贡献只和每个循环的大小有关,可以枚举n的正整数拆分,然后对每种拆分计算对应的置换个数。具体来说,记有m个循环,每个循环的长度为li,每个长度的循环有ci个。首先给每个循环分配一个位置

(nl1)(nl1l2)(nl1lm1lm)=n!li!

然后,固定第一个元素,每个循环有(li1)!种排法。同时,相同长度的循环彼此之间的顺序被重复考虑。所以最后的答案是
n!lici
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int p=997;
int n,ans,fac[65],inv[65],invfac[65],cnt[65],a[65],gcd[65][65],node;
int pow(int base,int k)
{
    int ret=1;
    for (;k;k>>=1,base=base*base%p)
        if (k&1) ret=ret*base%p;
    return ret;
}
int getgcd(int x,int y)
{
    if (gcd[x][y]) return gcd[x][y];
    return gcd[x][y]=y?getgcd(y,x%y):x;
}
void check()
{
    int ret=fac[n],tot=0,sum=0;
    for (int i=1;i<=n;i++)
    {
        ret=ret*invfac[cnt[i]]%p;
        for (int j=1;j<=cnt[i];j++)
            a[++tot]=i,ret=ret*inv[i]%p;
    }
    for (int i=1;i<=tot;i++)
    {
        sum+=a[i]/2;
        for (int j=i+1;j<=tot;j++) sum+=gcd[a[i]][a[j]];
    }
    ret=ret*pow(2,sum)%p;
    ans=(ans+ret)%p;
}
void dfs(int now,int num)
{
    //node++;
    if (now==1)
    {
        cnt[1]=n-num;
        check();
        return;
    }
    for (int i=0;num+i*now<=n;i++)
    {
        cnt[now]=i;
        dfs(now-1,num+i*now);
    }
}
int main()
{
    scanf("%d",&n);
    fac[0]=invfac[0]=1;
    for (int i=1;i<=n;i++)
    {
        fac[i]=fac[i-1]*i%p;
        inv[i]=pow(i,p-2);
        invfac[i]=pow(fac[i],p-2);
    }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            gcd[i][j]=getgcd(i,j);
    dfs(n,0);
    //printf("%d\n",node);
    printf("%d\n",ans*invfac[n]%p);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值