题目链接:https://vjudge.net/contest/332708#problem/Q
题目大意:
n 个珠子组成的 项链,t 种颜色去染, 问有多少本质不同的项链;
经旋转,翻转一样的视为同一种项链。
题解:等价类计数问题,用Polya定理和burnside定理解决。
代码有详解。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define rp(i, s, t) for (i = s; i <= t; i++)
#define RP(i, s, t) for (i = t; i >= s; i--)
#define ll long long
#define ull unsigned long long
using namespace std;
inline int read()
{
int x = 0, t = 1;
char ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-')
ch = getchar();
if (ch == '-')
t = -1, ch = getchar();
while (ch <= '9' && ch >= '0')
x = x * 10 + ch - 48, ch = getchar();
return x * t;
}
inline void write(int x)
{
char F[200];
int tmp = x > 0 ? x : -x;
if (x < 0)
putchar('-');
int cnt = 0;
while (tmp > 0)
{
F[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while (cnt > 0)
putchar(F[--cnt]);
}
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
/*总共有两种情况:旋转和翻转
旋转:逆时针旋转i颗珠子的间距,则珠子0,i,2i,....构成一个循环,循环内有n/gcd(i,n)个元素
一共有gcd(i,n)个循环,那么根据Polya定理:不动点个数 a=∑(t^(gcd(i,n))) {0<=i<=n-1}
翻转:分为两种情况讨论,n为奇数和n为偶数
当n为奇数时,对称轴为n条,每条对称轴形成(n-1)/2个长度为2的循环和1个长度为1的循环,即(n+1)/2个循环((n-1)/2+1).
所以这些置换的不动点个数为 b = n*t^( (n+1)/2 ).
当n为偶数时,有两种对称轴:穿过珠子和不穿过珠子
穿过珠子时,对称轴为n/2条,形成n/2-1个长度为2的循环和两个长度为1的循环。
不穿过珠子时,对称轴为n/2条,形成n/2个长度为2的循环
故n为偶数时置换的不动点的个数为 b = n*(t^(n/2+1)+t(n/2))/2;
*/
int main()
{
int n, t;
while (n = read(), t = read())
{
if (!n)
break;
ull pow[100]; //数组用unsigned long long 来存储,不然会炸
pow[0] = 1;
int i;
rp(i, 1, n) pow[i] = pow[i - 1] * t; //预处理求出t的幂次方
ull a = 0;
rp(i, 0, n - 1) a += pow[gcd(i, n)]; //旋转的情况
ull b = 0;
//翻转的情况
if (n & 1)
b = n * pow[(n + 1) / 2]; //n为奇数
else
b = n / 2 * (pow[n / 2 + 1] + pow[n / 2]); //n为偶数
printf("%llu %llu\n", a / n, (a + b) / 2 / n);
}
return 0;
}