【ybt金牌导航8-5-2】彩色项链2
彩色项链2
题目链接:ybt金牌导航8-5-2
题目大意
m 个颜色的珠子,可以放 n 个组成项链,问你能做出多少个不重复的。
重复是当项链可以通过旋转和沿中轴线翻转可以完全相同。
思路
这道题跟——>这一道题<——差不多。
因为它 \(n,m\) 可能不一样,你会发现你之前用的化公式的方法就不能直接用上去。
但是它范围很小,那我们就暴力搞,那这个也不是问题。
但是它还有沿中轴线翻转的操作。
那我们也往 Polya 定理的方向上考虑。
那你遇到这种中间翻转的(比如回文串),就想到了奇偶分类。
如果长度是奇数,那就一定中轴线一定要碰到一个点(也只能碰到一个),那就有 \((n-1)/2\) 个两个点的循环 \(1\) 个一个点的循环,那就是 \((n+1)/2\) 个循环。然后每个点都可以作为被中轴线碰到的点,那就一共有 \(n\) 个这样的置换。
如果长度是偶数,那你会想到可以分两种可能:中轴线什么都碰不到,中轴线碰到了两个点。
那两个都各有 \(n/2\) 个这样的置换,什么都碰不到的循环有 \(n/2\) 个,碰到两个的循环有 \(2+(n-2)/2=(n+2)/2\) 个。
那按着这么算就好了。
(记得总的置换个数有 \(2\times n\) 个)
代码
#include<cstdio>
#define ll long long
using namespace std;
int n, m;
ll ans;
void csh() {
ans = 0;
}
ll gcd(ll x, ll y) {//求gcd
if (!y) return x;
return gcd(y, x % y);
}
ll ksm(ll x, ll y) {//快速幂
ll re = 1;
while (y) {
if (y & 1) re = re * x;
x = x * x;
y >>= 1;
}
return re;
}
int main() {
scanf("%d %d", &m, &n);
while (m || n) {
csh();
for (int i = 1; i <= n; i++) {
ans += ksm(m, gcd(i, n));//旋转
}
if (n & 1) ans += n * ksm(m, (n + 1) / 2);//沿中轴线翻转(分奇偶讨论)
else ans += n / 2 * ksm(m, n / 2) + n / 2 * ksm(m, (n + 2) / 2);
ans /= n * 2;
printf("%lld\n", ans);
scanf("%d %d", &m, &n);
}
return 0;
}