【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;
}
posted @ 2021-02-26 21:35  あおいSakura  阅读(38)  评论(0编辑  收藏  举报