一、相关概念
1、置换:如果记A[i]为置换A的第i个元素,那么对一个排列进行置换A这个操作,表示将原先第i个位置上的数字挪到第A[i]个位置。如(2,3,1)表示第一个位置上的数字移动到第二个位置上,第二个位置上的数字移动到第三个位置上,第三个位置上的数字移动到第一个位置上。
2、置换乘法:依次进行两个置换所得到的结果。注意:乘法满足结合律,不满足交换律。如(2,3,1)*(1,3,2)=(3,2,1)
3、置换分解:将置换第i个位置上的数字挪到第A[i]个位置表示成i->A[i]的图,则一个置换可以分解为多个环,每个置换都写成不相交循环的乘积。如:(1,3,2)=(1)(3,2)其中(1)与(3,2)分别为一个环。
4、等价类计数问题:题目中会定义一类等价关系,满足等价关系的元素被看成同一类,只统计一次。
5、置换的不动点:如果一个值经过置换后位置不变,则称这个值(位置)为这个置换的不动点。如:(1,3,2)的不动点为1。
6、burnside引理: 等价类计数问题中不同本质的方案数等于每个置换的不动点个数之和。
7、polay定理:用于快速求每个置换的不动点个数。将置换f分解成m(f)个循环的乘积,并假设涂k种颜色的话,所有置换的k^m(f)的平均值就是等价类的个数。
二、例题
1、UVA-10294
题意:n颗珠子t种颜色,求有多少种项链和手镯,项链不可以翻转,手镯可以翻转。
题解:对于旋转操作,我们可以旋转0,1,2,...,n-1个珠子,每个旋转对应的置换群的循环节个数为gcd(i,n),现涂t种颜色,所以所有置换循环节个数的和为sum(t^gcd(i,n))。
对于翻转操作,如果n为奇数,则其中一个点为不动点,其他点分两个为一个循环节,形如(1)(2,3)(4,5)...(n-1,n),所以每个置换的循环节个数为n/2+1。共有n个置换,所以,所有置换循环节个数的和为n*t^(n/2+1)。
如果n为偶数,则其中两个点为不动点或者没有不动点,形如(1)(2)(3,4)...(n-1,n)或(1,2)(3,4)...(n-1,n),所以每个置换的循环节个数为n/2+1或n/2。共有n个置换,但循环节会重复。所以,所有置换的和为(n/2)*(t^(n/2+1)+t^(n/2))。
因为对于手镯来说可以旋转也可以翻转,所以一共有2*n个置换,所以等价类个数=(旋转置换循环节个数+翻转置换循环节个数)/(2*n)。
对于项链来说只能旋转,所以一共有n个置换,所以等价类个数=旋转置换循环节个数/n。
#include
#define lowbit(x) (x&(-x))
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pii;
const int maxn = 1e5 + 10;
const int maxm = 1e6 + 10;
const int mod = 1e9 + 7;
const int inf = 2e9 + 7;
const double dinf = 10000000007.0;
ll p[maxn];
int main() {
#ifdef LOCAL
freopen("input.in", "r", stdin);
// freopen("out.in", "w", stdout);
#endif // LOCAL
int n,t;
while(~scanf("%d%d",&n,&t)){
p[0] = 1LL;
for(int i = 1; i <= n; i++) p[i] = (ll)t * p[i - 1];
ll a = 0;
for(int i = 1; i <= n; i++) a += p[__gcd(i,n)];
ll b = 0;
if(n % 2 == 1) b = (ll)n * p[n/2+1];
else b = (ll)n/2 * (p[n/2] + p[n/2+1]);
printf("%lld %lld\n",a / (ll)n, (a + b) / (2LL * n));
}
return 0;
}