zoukankan      html  css  js  c++  java
  • POJ 2409 Let it Bead:置换群 Polya定理

    题目链接:http://poj.org/problem?id=2409

    题意:

      有一串n个珠子穿起来的项链,你有k种颜色来给每一个珠子染色。

      问你染色后有多少种不同的项链。

      注:“不同”的概念是指无论怎样旋转或翻转项链,都与之前的不同。

    题解:

      本题用到了置换的相关知识:

        (1)Burnside引理:

          等价类数目 = 所有C(f)的平均值 (C(f)为置换f的不动点数目)

        

        (2)置换f可以分解成m(f)个循环的乘积,假设涂k种颜色:

          C(f) = k^m(f)

        

        (3)Polya定理:(综上)

          等价类数目 = 所有k^m(f)的平均数

      考虑两种操作,旋转和翻转:

        (1)旋转:

          先假定所有的旋转都是顺时针(逆时针也一样)。

          那么对于旋转这个操作,总共有n个置换:

            不旋转(旋转0格)、顺时针旋转1格(1个珠子的距离)、2格、3格...n-1格。

          所以现在要算的就是每个置换f的m(f),然后使用Polya定理。

          旋转i格:m(f) = gcd(n,i)

          所以sum += ∑( k^gcd(n,i) ) (0<=i<=n-1)

        (2)翻转:

          有两种情况,n为奇数或偶数。

            1.偶数:

              共有n个对称轴,也就是有n个置换。

              I. 其中,n/2个对称轴不穿过珠子。这种置换的m(f) = n/2 。

                所以sum += (n/2) * (k^(n/2))

              II.另外n/2的对称轴恰好经过2颗珠子。这种置换的m(f) = n/2 - 1 。

                所以sum += (n/2) * (k^(n/2-1))

              综上:sum += (n/2) * ( k^(n/2) + k^(n/2-1) )

            

            2.奇数:

              共有n个对称轴,也就是有n个置换。并且每个对称轴恰好经过一颗珠子。

              所有置换的m(f) = (n-1)/2

              所以sum += n * ( k^((n-1)/2) )

      

      呼。。。两种操作讨论完了。

      因为两种操作总共有2*n个置换。

      所以呢。。。

      答案是:sum/(2*n)  ヾ(๑╹◡╹)ノ"

    AC Code:

     1 // num of equivalence class = average C(f)
     2 // C(f) = k ^ m(f)    ->    num of fixed points
     3 // m(f) = circle num in each permutation
     4 
     5 #include <iostream>
     6 #include <stdio.h>
     7 #include <string.h>
     8 #define MAX_N 40
     9 
    10 using namespace std;
    11 
    12 int n,t;
    13 int POW[MAX_N];
    14 
    15 int gcd(int a,int b)
    16 {
    17     return b==0?a:gcd(b,a%b);
    18 }
    19 
    20 int main()
    21 {
    22     while(cin>>t>>n)
    23     {
    24         if(n==0 && t==0) break;
    25         POW[0]=1;
    26         for(int i=1;i<=n;i++)
    27         {
    28             POW[i]=POW[i-1]*t;
    29         }
    30         int sum=0;
    31         // rotate
    32         for(int i=0;i<n;i++)
    33         {
    34             sum+=POW[gcd(n,i)];
    35         }
    36         // overturn
    37         if(n&1) sum+=n*POW[(n+1)/2];
    38         else sum+=(n/2)*(POW[n/2+1]+POW[n/2]);
    39         cout<<sum/(2*n)<<endl;
    40     }
    41 }
  • 相关阅读:
    luogu题解 P2184 【贪婪大陆】
    luogu题解 P3763 【[TJOI2017]DNA】
    实战技巧--对拍
    题解 P3620 【[APIO/CTSC 2007]数据备份】
    题解 UVA1316 【Supermarket】
    学习笔记-Rabin-Karp哈希
    题解 POJ1964/UVA1330/SP277 【City Game】
    题解 POJ 2559-SP1805 【HISTOGRA
    题解 P2859 【[USACO06FEB]摊位预订Stall Reservations】
    Linux操作系统(一)
  • 原文地址:https://www.cnblogs.com/Leohh/p/7385472.html
Copyright © 2011-2022 走看看