【Polya定理】BZOJ1488

本文探讨了Polya定理在解决边染色问题时的难点,重点在于处理点置换与边置换的关系。文章分为两种情况讨论:一是边的两端在同一个点循环内的染色,二是边的两端在不同点循环内的染色,并提供了相应的证明思路。通过这种方式,阐述了如何计算本质不同的染色方案数。

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

分析

据说很板的Polya定理的题。。。

可能我学了假的Polya。。。

首先回顾一下Polya定理的内容:
对n个染色位置的本质不同的染色方案数(即不能通过置换得到另一染色方案):

mck|G| ∑ m c k | G |

这里的k是指一种置换, ck c k 指这种置换的循环数。

当然,这个基础公式很多时候并不实用,因此还有一种计算方式:

apmp|G| ∑ a p ∗ m p | G |

这个就更加粗暴了,p是某种置换的循环个数, ap a p 指循环个数为 p p 个的置换有多少个。
这题就需要这个公式。

现在这题最大的难点是:置换是在点上的,然而染色是在边上的。

因此问题就是:如何处理点置换与边置换的对应关系。

把边置换分为两部分来看:边的两端在同一个点循环内的,边的两端在不同的点循环内的。

第一种情况

边循环大小为点循环大小的一半(向下取整)。
证明据说很直观:
枚举这个循环内的点置换(1+i,2+i,3+i,1) i[0,sum1]sum i ∈ [ 0 , s u m − 1 ] ( s u m 表 示 点 循 环 大 小 )
那么当 i>sum2 i > ⌊ s u m 2 ⌋ 时,就可以在 [0,sum2] [ 0 , ⌊ s u m 2 ⌋ ] 中找一个与它相同。

第二种情况

这两个点循环之间的边循环大小,为两个点循环大小的GCD。
证明据说也很简单。。可以画图来证明?
附一个大佬的博客。。她已经写得非常清楚了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 65
#define MOD 997
using namespace std;
int fsp(int x,int y){
    int res=1;
    while(y){
        if(y&1)
            res=res*x%MOD;
        x=x*x%MOD;  
        y>>=1;
    }
    return res;
}
int gcd(int x,int y){
    if(y==0)
        return x;
    return gcd(y,x%y);  
}
int a[MAXN],b[MAXN],fac[MAXN],ans,n,m;
void solve(int x,int sum,int cnt){
    if(sum==0){
        int res=0,add=1;
        for(int i=1;i<=cnt;i++){
            res+=(a[i]/2*b[i]+b[i]*(b[i]-1)/2*a[i])%(MOD-1);
            add=add*fac[b[i]]%MOD*fsp(a[i],b[i])%MOD;
            for(int j=i+1;j<=cnt;j++)
                res+=b[i]*b[j]*gcd(a[i],a[j]);
            res%=(MOD-1);
        }
        add=fac[n]*fsp(add,MOD-2)%MOD;
        ans+=add*fsp(m,res)%MOD;
        ans%=MOD;
        return ;
    }
    if(x==0)
        return ;
    for(int i=1;i*x<=sum;i++){
        a[cnt+1]=x;
        b[cnt+1]=i;
        solve(x-1,sum-i*x,cnt+1);   
    }
    solve(x-1,sum,cnt);
}
int main(){
    freopen("color.in","r",stdin);
    freopen("color.out","w",stdout);
    SF("%d%d",&n,&m);
    fac[0]=1;
    for(int i=1;i<=n;i++)
        fac[i]=fac[i-1]*i%MOD;
    solve(n,n,0);
    ans*=fsp(fac[n],MOD-2);
    ans%=MOD;
    PF("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值