题意:
给我们 m m m种不同颜色的珠子,每种颜色的珠子数量无限。现在我们要从中挑 n n n个珠子,穿成一个环形手链,问能够制造多少种不同的手链。如果两个手链经旋转或翻转后能够完全重合在一起,对应位置的珠子颜色完全相同,则视为同一种手链。
题解:
这道题目是 P o l y a Polya Polya定理的模板题。
对于这道题目,首先我们要考虑有几种置换方式。不难发现有两种,分别是旋转和翻转。
先分析旋转置换。
我们可以发现,根据一个珠子旋转的次数,这种置换方式总共有
n
n
n种情况,也就是一个珠子旋转
k
k
k次,其中
k
=
0
,
1
,
2
,
…
,
n
−
1
k=0,1,2,\dots,n-1
k=0,1,2,…,n−1。对于每种旋转,我们要分析总共有几个循环置换。
要想达到循环,必须要满足
x
+
k
t
≡
x
(
m
o
d
n
)
x+kt\equiv x(mod\ n)
x+kt≡x(mod n),其中
x
x
x就是要旋转的珠子的起始位置。其实也就是求这个正整数
t
t
t的最小取值,即对于旋转
k
k
k来说,最少经过几次旋转能够回到起始位置,也就是完成一次循环。上面的同余式可以转化为
k
t
≡
0
(
m
o
d
n
)
kt\equiv0(mod\ n)
kt≡0(mod n),再化简成
k
t
+
n
r
=
0
kt+nr=0
kt+nr=0,可以知道这个
t
t
t的最小取值就是
n
g
c
d
(
n
,
k
)
\frac n{gcd(n,k)}
gcd(n,k)n。现在求出了这个旋转的循环节长度,下面我们还要求出,
n
n
n个珠子总共有多少这样的循环,这个比较容易求,就是
n
n
g
c
d
(
n
,
k
)
=
g
c
d
(
n
,
k
)
\frac n{\frac n{gcd(n,k)}}=gcd(n,k)
gcd(n,k)nn=gcd(n,k)。因此,对于旋转置换来说,其不动点的个数就是
∑
k
=
0
n
−
1
m
g
c
d
(
n
,
k
)
\sum_{k=0}^{n-1}m^{gcd(n,k)}
∑k=0n−1mgcd(n,k)。
再分析翻转置换。
对于翻转置换,我们要考虑
n
n
n的奇偶性。
当
n
n
n是奇数时,只有这么一种翻转方式:
对于这种翻转方式,我们容易求出,其包含的循环置换个数总共有
n
+
1
2
\frac {n+1}2
2n+1。因此对于奇数情况,不动点的个数有
n
∗
m
n
+
1
2
n*m^{\frac {n+1}2}
n∗m2n+1。
当
n
n
n是偶数时,就存在两种翻转方式。首先第一种就是:
对于这种情况,循环置换的个数,有
n
2
+
1
\frac n2+1
2n+1个。此时的不动点个数就是
n
2
∗
m
n
2
+
1
\frac n2*m^{\frac n2+1}
2n∗m2n+1个。
第二种翻转方式是:
对于这种翻转方式,对应的不动点个数是
n
2
∗
m
n
2
\frac n2*m^{\frac n2}
2n∗m2n。
因此所有情况的总的不动点个数就是以上情况的不动点个数之和。对应的平均数就是总的不动点个数除以 2 n 2n 2n即可。
实现细节见代码:
#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int qpow(int a, int b) {
int ans = 1;
while (b) {
if (b & 1) {
ans = ans * a;
}
a = a * a;
b >>= 1;
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int m, n;
while (cin >> m >> n && (m || n)) {
int sum = 0;
int ans = 0;
for (int i = 0; i < n; i++) { // 旋转置换的不动点个数
int d = gcd(i, n);
ans += qpow(m, d);
}
// 翻转置换的不动点个数
if (n & 1) {
ans += qpow(m, (n + 1) / 2) * n;
}
else {
ans += qpow(m, n / 2 + 1) * n / 2 + qpow(m, n / 2) * n / 2;
}
cout << ans / (2 * n) << endl; // 求平均数
}
return 0;
}