zoukankan      html  css  js  c++  java
  • [SHOI2006] 有色图

    Description

    给一张 (n) 个点的无向完全图,同时还有 (m) 种颜色。要求给每条边染色,问有多少种不同的染色方案。两种方案不同当且仅当顶点标号任意重排后不同。(nleq 53)

    Solution

    好吧上课讲的题我还研究了一整个二晚的题解 上课睡觉就是不应该

    首先这题要求边的不同染色方案,如果要用 (burnside) 或者 (polya) 那一套的话需要求边的置换,但是判断方案是否相同又是点的置换。好吧我们考虑点的置换看看在中间能不能统计出来边的置换的方案数。

    把一个点置换搞出来,它含有若干轮换 ((a_1,a_2dots)(b_1,b_2dots)dots)

    考虑这若干轮换中的边置换产生的轨道数。分以下两种情况考虑:

    1. 考虑两个端点分别在两个轮换 (a,b) 中的边。设 (a,b) 的长度分别是 (l_1,l_2),那么总点数就是 (l_1cdot l_2) 个,循环节是 (operatorname{lcm}(l_1,l_2)),所以一共有 (gcd(l_1,l_2)) 个轨道。
    2. 对于两个端点在一个轮换 (a) 中的边,要分轮换的长度奇偶性来考虑。
      • 如果 (l_1) 是奇数,那么循环节是 (l_1),一共有 (C(l_1,2)) 个点对,所以一共有 (frac{l_1-1}2) 个轨道。
      • 如果 (l_1) 是偶数,那么循环节是 (l_1) 或者 (frac{l_1}2),因为两点的距离恰好是 (frac{l_1}2) 的时候循环节只能是 (frac{l_1}2) 就重复了。所以一共有 (frac{C(l_1,2)-frac{l_1}2}{l_1}+1=frac{l_1}2) 个轨道。

    最后要求的就是对于当前已经分好组的轮换组,有多少个置换满足这个条件。

    emmm这个就相当于把 (n) 个人分配到 (k) 个长度给定的独立的圆排列里,然后经过一番神仙推导得出总分配数为 (frac{n!}{prodlimits_{i=1}^k l_iprodlimits_{i=1}^n B_i!})。其中 (B_i)(l_x=i)(x) 的个数。

    最后记得除以 (n!)

    Code

    #include<bits/stdc++.h>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    const int N=60;
    #define inv(x) ksm(x,mod-2)
    
    int a[N],b[N];
    int l[N],fac[N];
    int n,m,mod,cnt,ans;
    
    int gcd(int a,int b){
        return b?gcd(b,a%b):a;
    }
    
    int ksm(int a,int b,int ans=1){
        while(b){
            if(b&1) ans=1ll*ans*a%mod;
            a=1ll*a*a%mod;b>>=1;
        } return ans;
    }
    
    int getint(){
        int X=0,w=0;char ch=getchar();
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    void solve(int n){
        memset(b,0,sizeof b);
        for(int i=1;i<=n;i++) b[l[i]]++;
        ll now=0;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                (now+=gcd(l[i],l[j]))%=mod;
        for(int i=1;i<=n;i++)
            (now+=l[i]/2)%=mod;
        ll noww=1;
        for(int i=1;i<=n;i++)
            (noww*=l[i])%=mod;
        for(int i=1;i<=::n;i++)
            (noww*=fac[b[i]])%=mod;
        ans=(1ll*ksm(noww,mod-2)*fac[::n]%mod*ksm(m,now)%mod+ans)%mod;
    }
    
    void dfs(int now,int res,int las){
        if(!res){solve(now-1);return;}
        for(int i=las;i<=res;i++){
            l[now]=i;
            dfs(now+1,res-i,i);
        }
    }
    
    signed main(){
        n=getint(),m=getint(),mod=getint();
        fac[0]=1;
        for(int i=1;i<=53;i++) fac[i]=1ll*fac[i-1]*i%mod;
        dfs(1,n,1);
        printf("%lld
    ",1ll*ans*inv(fac[n])%mod);
        return 0;
    }
    
    
  • 相关阅读:
    uoj311 【UNR #2】积劳成疾
    SQL中MAX()和MIN()函数的使用(比较字符串的大小)
    SQL Server 怎样生成序列号(虚拟数字辅助表)
    如何使用引用类型来改变变量的值
    C#获取当前主机硬件信息
    JS扫雷原理性代码
    Struts2文件的上传和下载实现
    Struts2拦截器详解
    Struts2拦截器配置和使用
    Struts2转换器配置和用法
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/10300619.html
Copyright © 2011-2022 走看看