本文是刘汝佳《算法竞赛入门经典——训练指南》的读书笔记。
解题思路:
对于项链,它只支持旋转置换;而手镯支持旋转和翻转。下面由这两种置换来研究本题。
旋转
设顺时针旋转 (i) 颗珠子的间距,则珠子 (0, i, 2i, ...) 构成一个循环。
设每个循环有 (t) 颗珠子,则这 (t) 颗珠子的编号分别为:(0, (i mod n), (2i mod n), ... [(t-1)i mod n]),我们不能推出:(ti mod n = 0),即 (ti = nk, k in Z).则(ti = nk) 的最小值为 (lcm(i,n)),故由 (ti = nk = lcm(i,n)) 得
(ti = frac{in}{gcd(i,n)})
(t = frac{n}{gcd(i,n)})
则循环数为(frac{n}{t} = gcd(i,n)).
不动点总数为 (a = sum_{i=0}^{i=n-1} t^{gcd(i,n)}).
翻转
分 (n) 为奇数偶数两种情况讨论:
若 (n) 为奇数,则对称轴有 (n) 条,每条对称轴形成 (frac{n-1}{2}) 个二元循环和 (1) 个一元循环,其总循环数为 (frac{n+1}{2}). 不动点总数为 (b = nt^{frac{n+1}{2}}).
若 (n) 为偶数,对称轴有两种,一种穿过两个对点,这种对称轴形成 (2) 个一元循环和 (frac{n}{2} - 1) 个二元循环;一种是穿过两条对边的中点,这种对称轴形成 (frac{n}{2}) 个二元循环。两种对称轴都有 (frac{n}{2}) 条,则不动点总数为 (b = frac{n}{2}(t^{frac{n}{2}}+t^{frac{n}{2}+1})).
则项链数为 (frac{a}{n}),手镯数为 (frac{a+b}{2n}).
AC代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 ll pows[100]; 6 ll gcd(ll a,ll b){ 7 if(b==0) return a; 8 return gcd(b,a%b); 9 } 10 int main(){ 11 ll n,t; 12 while(scanf("%lld%lld",&n,&t)==2){ 13 ll xuan=0; 14 pows[0]=1; 15 for(int i=1;i<=n;i++) pows[i]=pows[i-1]*t; 16 for(ll i=0;i<n;i++){ 17 ll g=gcd(i,n); 18 xuan+=pows[g]; 19 } 20 ll fan=0; 21 if(n%2==1) 22 fan=pows[(n+1)/2]*n; 23 else 24 fan=(pows[n/2]+pows[n/2+1])*n/2; 25 printf("%lld %lld ",xuan/n,(fan+xuan)/(2*n)); 26 27 } 28 29 30 return 0; 31 }