• Polya 定理入门[Burnside引理,Polya定理,欧拉函数]


    blogPolya,.这篇blog重点讨论Polya的应用, 更详细的证明请百度 .


    BurnsideBurnside引理

    L=1Gi=1GD(ai)L=frac{1}{|G|}sum_{i=1}^{|G|}D(a_i)

    LL: 本质不同的方案数.
    GG: 置换群集合.
    aia_i: 置换群中的第 ii 个置换.
    D(ai)D(a_i): 进行 aia_i 这个置换, 状态不会变化的方案 数量.

    该引理与下方内容没有太大关系, 可以暂时忽略.


    ProblemProblem 链接
    NN 个石子围成一圈, 使用 MM 种颜色染色, 求有多少种本质不同的方案.

    借此问题引入 PolyaPolya定理


    PolyaPolya定理

    L=1Gi=1GMC(gi)L=frac{1}{|G|}sum_{i=1}^{|G|}M^{C(g_i)}

    先丢出公式.

    这道题的 置换群 GG: 转00次, 转11次 …转 N1N-1 次, (皆为顺时针转动).
    若满足旋转 kk 个位置, 状态和原来相同, 那么 ii 位置颜色 等于 (i+k)%N(i+k)\%N 位置颜色,
    旋转 tt 次, 仍和原来位置相同, 即 ii 位置与 (i+tk)%N(i+t*k)\%N 位置颜色相同,
    ii 旋转 ttkk 次, 一定能回到原来位置, 即可以无限旋转,
    所以 ii 就与 所有 (i+tk)%N(i+t*k)\%N 位置呈现一个封闭的 color{red}{循环节}.
    设转了 tt 次后, 第一次回到 ii 位置, 则
    tk=lcm(k,N)=kNgcd(k,N)t * k=lcm(k, N)=frac{k*N}{gcd(k,N)},
    t=Ngcd(k,N) herefore t=frac{N}{gcd(k,N)},

    ttcolor{red}{循环节}长度, 则color{red}{循环节}数量为 Nt=gcd(k,N)frac{N}{t}=gcd(k,N).

    公式中 颜色的数量为 MM; 在 gig_i 置换下, 有 C(gi)C(g_i)color{red}{循环节}.

    此题中 C(gi)=gcd(k,N)C(g_i)=gcd(k,N), Ans=L=1Nk=0N1Mgcd(k,N) herefore Ans=L=frac{1}{N}sum_{k=0}^{N-1}M^{gcd(k,N)}


    1拓展 1

    假如上题增加 color{red}{对称同构}, 则意味着 原先的两个不同方案 对称 时计为一个方案,
    NN 的奇偶 分类讨论:

    1. NN 为奇数, 对称轴上有一个点, 循环节个数为 N+12frac{N+1}{2}, 总共有 NN 个对称轴置换, 则对答案贡献为 NMN+122Nfrac{N*M^{frac{N+1}{2}}}{2N}
      最后的答案为 Ans=L=12N(k=0N1Mgcd(k,N)+NMN+12)Ans=L=frac{1}{2N}(sum_{k=0}^{N-1}M^{gcd(k,N)}+N*M^{frac{N+1}{2}})

    2. NN 为偶数, 对称轴上可以没有点, 也可以有两个点, 两种对称轴都有 N2frac{N}{2} 种, 总共有 NN 个对称轴置换,
      对称轴上无点时, 循环节个数为N2frac{N}{2}, 对答案贡献为 MN22Nfrac{M^{frac{N}{2}}}{2N},总贡献为N2MN22Nfrac{frac{N}{2}*M^{frac{N}{2}}}{2N}.
      对称轴上有点时, 循环节个数为N2+1frac{N}{2}+1, 对答案贡献为 MN2+12Nfrac{M^{frac{N}{2}+1}}{2N}, 总贡献为 N2MN2+12Nfrac{frac{N}{2}*M^{frac{N}{2}+1}}{2N}.

      所以最后的答案为
      Ans=L=12N(k=0N1Mgcd(k,N)+N2MN2+N2MN2+1)Ans=L=frac{1}{2N}(sum_{k=0}^{N-1}M^{gcd(k,N)}+frac{N}{2}*M^{frac{N}{2}}+frac{N}{2}*M^{frac{N}{2}+1})


    2拓展2

    N<=109color{red}{N<=10^9} , O(N)O(N)计算下式会 TLETLE, 需要更快的办法,
    Ans=L=1Nk=0N1Mgcd(k,N)Ans=L=frac{1}{N}sum_{k=0}^{N-1}M^{gcd(k,N)}

    由于 gcd(k,N)Ngcd(k,N)|N, 而NN的约数不会超过 2N2sqrt{N} 个,
    考虑枚举 dd, (dN)(d|N)
    则就只需统计 gcd(k,N)=dgcd(k,N)=dkk 的个数.
    d=gcd(k,N)=gcd(dt,dNd)d=gcd(k,N)=gcd(d*t, d*frac{N}{d})
    ttNdfrac{N}{d} 互质, 即 gcd(t,Nd)=1color{red}{gcd(t, frac{N}{d}) = 1}.
    φ(Nd) herefore color{red}{varphi(frac{N}{d})} 即为 gcd(k,N)=dgcd(k,N)=dkk 的个数.

    于是 Ans=L=1NdNφ(Nd)MdAns=L=frac{1}{N}sum_{d|N}varphi(frac{N}{d}) *M^d
    .

    φ(x)?如何求解 varphi(x)?
    根据定义: φ(x)=xpix(11pi)varphi(x)=xprod_{p_i|x}(1-frac{1}{p_i})
    通分得: φ(x)=xpixpi1pivarphi(x) = xprod_{p_i|x}frac{p_i-1}{p_i}
    按上式实现, 时间复杂度小于 O(N)O(sqrt{N}), 均摊 O(logN)?O(logN)?
    这里给出求解函数,

    int Get_phi(int x){
        int s = x;
        for(int i = 2; i*i <= x; i ++)
            if(x % i == 0){ //找到一个质因数
                s = s/i*(i-1);
                while(x%i == 0) x /= i;
            }
        if(x > 1) s = s/x*(x-1);	//不可能出现两个大于 sqrt(N) 的质因数, 所以只可能剩下一个, 处理掉就好 .
        return s;
    }
    

    所以 O(N),O(logN)O(sqrt{N}),O(logN) 分别求出所有约数 ddφ(Nd)varphi(frac{N}{d}) 即可, 时间复杂度 O(NlogN)O(sqrt{N}logN).


    Codemathcal{Code}

    #include<bits/stdc++.h>
    #define reg register
    
    const int mod = 1e9 + 7;
    
    int T;
    int N;
    
    int phi(int x){
            int s = x;
            for(reg int i = 2; i*i <= x; i ++)
                    if(x % i == 0){
                            s = s/i * (i-1);
                            while(x % i == 0) x /= i;
                    }
            if(x > 1) s = s/x * (x-1);
            return s;
    }
    
    int KSM(int a, int b){
            int s = 1; a %= mod;
            while(b){
                    if(b & 1) s = 1ll*s*a % mod;
                    a = 1ll*a*a % mod, b >>= 1;
            }
            return s;
    }
    
    void Work(){
            scanf("%d", &N);
            int Ans = 0;
            int lim = sqrt(N);
            for(reg int d = 1; d <= lim; d ++){
                    if(N % d) continue ;
                    Ans = ( 1ll*Ans + (1ll*phi(N/d) * KSM(N, d) % mod) ) % mod;
                    int d_2 = N / d;
                    if(d_2 == d) continue ;
                    Ans = ( 1ll*Ans + (1ll*phi(N/d_2) * KSM(N, d_2) % mod) ) % mod;
            }
            printf("%d
    ", (1ll*Ans*KSM(N, mod-2)) % mod);
    }
    
    int main(){
            scanf("%d", &T);
            while(T --) Work();
            return 0;
    }
    

    例题

    更多例题请戳 这里 .


  • 相关阅读:
    navicat for mysql (本人亲测,真实有效)
    python 8 days
    python 19 days
    python 20 days
    python 21 days
    python 10 days
    python 9 days
    python 14 days
    python 15 days
    python 16 days
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822588.html
Copyright © 2020-2023  润新知