zoukankan      html  css  js  c++  java
  • UVA10294项链和手镯(等价类计数问题)

    题意:
          给你一串珠子(连接成了一个环),共有n个珠子组成,你有t种颜色,现在你来给这个珠子染色,问染成项链有多少种方法?染成手镯有多少种方法?在项链里,经过顺时针旋转后相同的算一个,在手镯里,经过顺时针旋转或者沿着对称轴兑换后一样的算一个。


    思路:
          比较典型的等价类计数问题,我们定义两个变量,a是旋转的总个数,b是翻转的总个数,那么根据Burnside和Polya定理,a = C[0] + C[1] + C[2] +..+C[n-1];
    C[i]表示的是顺时针移动i个后的种类数,C[i] = t^w,t是颜色种类,w是循环节个数,在这个题目里,旋转是的循环节个数为gcd(i ,n);至于为什么可以自己想,想不通的话可以想想杭电上那个切蛋糕的题目,那么C[i] = t^gcd(i ,n)这样就能求出各个C[i]然后求出a,此时的相连的答案已经出来了,就是a/n,那么b呢?b可以分情况讨论,如果n是奇数那么对角线一共有n条,每次可以分出来(n+1)个循环节,那么b = n * t ^ ((n + 1)/2)如果n是偶数的话有两种情况,不穿过任何点的为 n/2*t(n/2) 穿过两个点的对角线为n/2*(n/2+1)那么此时的b=n/2*(t^(n/2) + t^(n/2+1)),那么手镯的种类为(a+b)/(n*2).


    这里在解释下上面的那两个定理,那两个定理是求等价类计数问题的常用定理,大体意思就是说种类数等于所有可能置换方法的方法数的平均数,而每一个置换方法的个数等于颜色个数的循环节次幂,循环节就是置换里面的那个循环节。


    #include<stdio.h>


    long long gcd(long long a ,long long b)
    {
       return a % b == 0 ? b : gcd(b ,a % b);
    }




    int main ()
    {
       long long pow[60];
       long long n ,t ,i;
       long long a ,b;
       while(~scanf("%lld %lld" ,&n ,&t))
       {
          pow[0] = 1;
          for(i = 1 ;i <= n ;i ++)
          pow[i] = pow[i-1] * t;
          a = 0;
          for(i = 0 ;i < n ;i ++)
          a += pow[gcd(i ,n)];
          if(n & 1) b = n * pow[(n+1)/2];
          else b = n / 2 * pow[n/2] + n / 2 * pow[n/2 + 1]; 
          printf("%lld %lld " ,a / n ,(a + b) / n / 2);
       }
       return 0;
    }     





  • 相关阅读:
    C/C++之文件打开方式差别
    C/C++获取文件大小
    dedecms使用
    TCP/IP概念简述
    protobuf新增message报错:类型已存在
    亚马逊MWS开发套路演示
    请求MWS报错401:Access Denied
    敏捷开发
    过滤器和拦截器的区别
    防盗链
  • 原文地址:https://www.cnblogs.com/csnd/p/12062588.html
Copyright © 2011-2022 走看看