【ybt金牌导航8-5-2】彩色项链2

彩色项链2

题目链接:ybt金牌导航8-5-2

题目大意

m 个颜色的珠子,可以放 n 个组成项链,问你能做出多少个不重复的。
重复是当项链可以通过旋转和沿中轴线翻转可以完全相同。

思路

这道题跟——>这一道题<——差不多。

因为它 n , m n,m n,m 可能不一样,你会发现你之前用的化公式的方法就不能直接用上去。
但是它范围很小,那我们就暴力搞,那这个也不是问题。

但是它还有沿中轴线翻转的操作。
那我们也往 Polya 定理的方向上考虑。
那你遇到这种中间翻转的(比如回文串),就想到了奇偶分类。

如果长度是奇数,那就一定中轴线一定要碰到一个点(也只能碰到一个),那就有 ( n − 1 ) / 2 (n-1)/2 (n1)/2 个两个点的循环 1 1 1 个一个点的循环,那就是 ( n + 1 ) / 2 (n+1)/2 (n+1)/2 个循环。然后每个点都可以作为被中轴线碰到的点,那就一共有 n n n 个这样的置换。

如果长度是偶数,那你会想到可以分两种可能:中轴线什么都碰不到,中轴线碰到了两个点。
那两个都各有 n / 2 n/2 n/2 个这样的置换,什么都碰不到的循环有 n / 2 n/2 n/2 个,碰到两个的循环有 2 + ( n − 2 ) / 2 = ( n + 2 ) / 2 2+(n-2)/2=(n+2)/2 2+(n2)/2=(n+2)/2 个。

那按着这么算就好了。
(记得总的置换个数有 2 × n 2\times n 2×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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/114154083