poj 1286 Necklace of Beads 题解

传送门


【题意】

给定 (n) 个空位待填的圆环,每个空位可以填入红、蓝、绿任一颜色的珠子。问不同构的方案数为多少?

题目认为旋转、沿坐标轴翻转后相同的两个方案是同构的。

(n<24)


【分析】

比较裸的 Polya 定理

旋转和翻转,以及这两个变换的运算构成一个群 (G)

而原本的翻转只能沿坐标轴翻转,但我们考虑先将圆环旋转 (- heta) 度的变换 (rot_{- heta}),再沿 (x) 轴翻转 (sym_0) ,最后再旋转 ( heta)(rot_{ heta}) ,则等价于圆环沿 ( heta) 的这条极径进行了翻转 (sym_{ heta})。即 (sym_{ heta}=rot_{ heta}circ sym_{0}circ sym_{- heta})

由于 (rot_{ heta}, sym_{0}, rot_{- heta}in G), 根据运算的封闭性,(sym_{ heta}in G) 。即群内包括了任意角度的旋转,和任意角度的翻转。

现考虑到旋转角度只有 (kcdot {2piover n}, kin{0, 1, 2, cdots, n-1}) 时才有意义,翻转角度只有 (kcdot {piover n}, kin{0, 1, 2, cdots, n-1}) 时才有意义

当旋转角度为 (kcdot {2piover n}) 时,构成置换 (left( egin{matrix} 1&2&3&cdots &n-k&n-k+1&cdots &n \\ k+1&k+2&k+3&cdots&n&1&cdots &k end{matrix} ight)),可拆解成 (gcd(k, n)) 个不可拆解的置换

(n) 为奇数时,翻转角度 (kcdot {piover n}) 使得除了直线上一点,其余每个点与关于直线的对称点构成一个置换,故可拆解成 (lceil{nover 2} ceil={n+1over 2}) 个不可拆解的置换

(n) 为偶数时,若 (k) 为奇数,则翻转角度 (kcdot {piover n}) 使得每个点与关于直线的对称点构成一个置换,可分解为 ({nover 2}) 个不可拆解的置换

(n) 为偶数时,若 (k) 为偶数,则翻转角度 (kcdot {piover n}) 使得除线上的两个点,每个点与关于直线的对称点构成一个置换,可分解为 (({nover 2}+1)) 个不可拆解的置换

故根据 Polya 定理:

(n) 为奇数时,方案数为 (displaystyle {1over 2n}(sum_{i=0}^{n-1} 3^{gcd(i, n)} + sum_{i=0}^{n-1} 3^{n+1over 2})={1over 2n}(sum_{i=0}^{n-1} 3^{gcd(i, n)} + ncdot 3^{n+1over 2}))

(n) 为偶数时,方案数为 (displaystyle {1over 2n}(sum_{i=0}^{n-1} 3^{gcd(i, n)} + sum_{i=0}^{n-1}3^{nover 2}[2 mid n]+sum_{i=0}^{n-1}3^{{nover 2}+1}[2mid n])={1over 2n}(sum_{i=0}^{n-1} 3^{gcd(i, n)} + 2ncdot 3^{nover 2}))

到这一步已经可以出答案了,不过本人顺着莫比乌斯反演推了推:

(displaystyle sum_{i=0}^{n-1} 3^{gcd(i, n)}=sum_{i=1}^n 3^{gcd(i, n)}=sum_{dmid n}3^dsum_{i=1}^n[gcd(i, n)=d]=sum_{dmid n}3^doldsymbol varphi({nover d}))


【代码】

本来是想 Python 直接冲的,猛地发现 POJ 不能交 Python,这里就直接敲了个表,然后 C++ 交上去

phi = [0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, 12, 10, 22, 8, 20, 12, 18, 12, 28, 8, 30]
pow3 = [1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 1594323, 4782969, 14348907, 43046721, 129140163, 387420489, 1162261467, 3486784401, 10460353203, 31381059609, 94143178827, 282429536481, 847288609443, 2541865828329, 7625597484987, 22876792454961, 68630377364883, 205891132094649, 617673396283947]
ans = [0]

for i in range(1, 32) :
    tmp = 0
    for d in range(1, i+1) :
        if i%d == 0 :
            tmp += 3**d*phi[i//d]
    if i&1 :
        tmp += i*3**((i+1)//2)
    else :
        tmp += i*2*3**(i//2)
    tmp //= 2*i
    ans.append(tmp)

print('ans[]={', end='0')
for i in range(1, 32) :
    print(', %d'%ans[i], end='')
print('};')