题目地址: http://poj.org/problem?id=2409
给你一串珠子有m个,用n种不同的颜色涂色,问有多少种分法。
用polay定理求解,对于排成一排的带编号的小球,按照某一种方案改变其中一些球的放置顺序,可以称之为置换。每一种置换方法可以用两排数字來表示,第一排数字和第二排数字一一对应,第一排数字表示小球的原来位置(1~n),第二排数字表示小球交换后的位置。现在我们有n个小球,m种颜色。有k种置换方法,我们认为能通过置换方法交换位置后变成同一种染色情况(颜色的排列状况相同,忽略小球编号),则我们认为这些互相通过置换能达到的状态为同一种染色方法。我们现在要求总共有多少种染色方法。要计算方法数,我们先要计算k种置换方法中每种置换方法中含有的环数,即建立一个图,有n个点,把每个置换方法两排数字中的上下一一对应的数字对看成边的起点和终点,计算这个图中有几个环。我们设环数分别为c1~ck。那么染色方法数为(m^c1+m^c2+...+m^ck)/k。以上就是polya定理,这里要注意的是置换方法集合必须是群,需要满足封闭性,即如果把通过该集合中的若干个方法连续进行置换压缩成一个置换方法(用两排数子表示),那么这种新的置换方法也必须属于该集合。
代码如下:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <vector> #include <list> #include <deque> #include <queue> #include <iterator> #include <stack> #include <map> #include <set> #include <algorithm> #include <cctype> using namespace std; typedef long long LL; const int N=21; const LL II=1000000007; int m,n; int ans,k; int gcd(int a,int b) { while(b) { a=a%b; swap(a,b); } return a; } int main() { int i; while(scanf("%d %d",&m,&n)&&(n+m)) { ans=0; for(i=1;i<=n;i++) { k=pow((double)m,gcd(n,i)); ans+=k; } if(n&1==1) ans+=n*pow((double)m,(n>>1)+1); else ans+=(n>>1)*pow((double)m,(n>>1))*(m+1); printf("%d ",ans/2/n); } return 0; }