• bzoj 1815


    polya定理板子题...

    其实本题难度并不大,但是对我这种初学群论的蒟蒻还是很大一个挑战

    首先看见这种带同构的计数,我们应该先把polya扔进来

    $ans=frac{1}{|G|}sum_{i=1}^{|G|}m^{c(p_{i})}$

    然后我们挨个去找就好了

    $G$显然是一个对应边置换的置换群

    m是已知,不用管,$|G|=n!$(一个点置换唯一对应一个边置换,因此边置换群的大小与点置换群的大小相等)

    因此有一个最暴力的思想,就是每次$O(n!)$枚举所有置换进行计算,这样做...显然过不去这道题

    因此我们换一种思想:

    我们发现,本题真正的难点是:我们每次置换的方式是对点进行置换,而在计算时需要用的是边的置换!

    因此首先我们要找到一个点的置换与边的置换的对应关系

    怎么对应?

    我们设一个点置换为$(a_{1},a_{2},...a_{n})(b_{1},b_{2}...b_{m})...$

    则边可以被分为两类:

    一.边的两个端点在同一个循环中

    设一个循环中点的个数为$v_{i}$,那么这个循环中对应的边的个数显然是$C_{v_{i}}^{2}$,而为了研究这些边所在的等价类数,我们将这些点均匀分布在一个圆周上,那么在循环的作用下每条边都会沿圆周移动,那么移动的两条边不能重合当且仅当两条边长度不同(这里的边长都指圆上劣弧长),那么这个边集中一共有$frac{v_{i}}{2}$个等价类

    二.边的两个端点不在同一个循环中

    设两个循环中点的个数分别为$v_{i}$,$v_{j}$,那么这两个点集相互间能组成的边的个数为$v_{i}v_{j}$,对于一条边,在经过$LCM(v_{i},v_{j})$次置换后会回到本身,因此总的循环个数应该为$gcd(v_{i},v_{j})$

    因此,对于一组给出的点的置换,设这组置换的循环节数量为$k$,那么这组点置换对应的边置换的循环节个数为$sum_{i=1}^{k}frac{v_{i}}{2}+sum_{i=1}^{k}sum_{j=i+1}^{k}gcd(i,j)$

    那么这一组边置换对应的贡献也就是$m^{sum_{i=1}^{k}frac{v_{i}}{2}+sum_{i=1}^{k}sum_{j=i+1}^{k}gcd(i,j)}$

    可是如果我们这么找,仍然会有$n!$个置换来计算,这样做还是会T

    但是我们不难发现,边置换的贡献只与其结构有关,而结构相同的点置换一定会导出结构相同的边置换!

    因此我们只需枚举所有点置换的结构即可

    再考虑:对于每一个点置换,都满足一个表达式:$sum_{i=1}^{k}v_{i}=n$

    那么一个点置换的结构不就是n的一个拆分嘛

    考虑n很小,所以我们可以爆搜一发n的拆分

    但是...具有这种结构的点置换一共会有多少个呢?

    令$B_{i}$表示这种结构下大小相同的循环的个数,则结论某一种结构的点置换个数是$S=frac{n!}{prod_{i=1}^{k}v_{i}*prod_{i=1}^{k}B_{i}!}$

    于是答案也就来了:

    $ans=frac{1}{n!}sum S*m^{sum_{i=1}^{k}frac{v_{i}}{2}+sum_{i=1}^{k}sum_{j=i+1}^{k}gcd(i,j)}$

    贴代码:

    #include <cstdio>
    #define ll long long
    using namespace std;
    ll n,m,p;
    ll mul[65];
    ll num[65];
    ll GCD[65][65];
    ll ret=0;
    ll pow_mul(ll x,ll y)
    {
        ll ans=1;
        while(y)
        {
            if(y&1)ans=ans*x%p;
            x=x*x%p,y>>=1;
        }
        return ans;
    }
    ll gcd(ll x,ll y)
    {
        return y?gcd(y,x%y):x;
    }
    void init()
    {
        mul[0]=mul[1]=1;
        for(ll i=2;i<=n;i++)mul[i]=mul[i-1]*i%p;
        for(ll i=1;i<=n;i++)for(ll j=i;j<=n;j++)GCD[i][j]=GCD[j][i]=gcd(i,j);
    }
    ll get_ans(int ttop)
    {
        ll sum=0,fm=1,cnt=0;
        for(int i=1;i<=ttop;i++)
        {
            sum=sum+(num[i]>>1),fm=(fm*num[i]%p);
            if(num[i]!=num[i-1])fm=fm*mul[cnt]%p,cnt=1;
            else cnt++;
            for(int j=i+1;j<=ttop;j++)sum=sum+GCD[num[i]][num[j]];
        }
        fm=fm*mul[cnt]%p;
        ll S=pow_mul(fm,p-2);
        return S*pow_mul(m,sum)%p;
    }
    void dfs(int dep,ll ed,ll las)
    {
        if(!ed)ret=(ret+get_ans(dep-1))%p;
        else
        {
            for(ll i=las;i<=(ed>>1);i++)
            {
                num[dep]=i;
                dfs(dep+1,ed-i,i);
                num[dep]=0;
            }
            num[dep]=ed;
            dfs(dep+1,0,ed);
            num[dep]=0;
        }
    }
    int main()
    {
        scanf("%lld%lld%lld",&n,&m,&p);
        init();
        dfs(1,n,1);
        printf("%lld
    ",ret);
        return 0;
    }
  • 相关阅读:
    Log4net使用总结,防止自定义的logger和root重复写入日志
    如何实现asp.net中FileUpload文件类型过滤功能
    C# 中 SerialPort.GetPortNames 获取串口号错误的问题及解决方法
    GOF 设计模式 [转载]
    CSS常用字体属性(多出的文本隐藏,或者以省略号的形式显示)和背景样式以及背景图的2个不常用属性:backgroundorigin和backgroundclip
    关于CSS各种选择器,还有各种引入样式表的区别,import导入样式表,在介绍一些伪类选择器
    MV*详解
    简易刮刮乐源码
    Gulp开发教程
    小程序的那些坑
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10964293.html
Copyright © 2020-2023  润新知