Polya定理是组合数学中一个重要的计数定理。设G为n个对象的一个置换群,用m种颜色对这n个对象染色,不同的方案数为:
,其中c(gi)为第i个置换的循环节数。
poj2409 有m种颜色且数量不限的珠子,将这些珠子做成长度为n的项链,问能做成多少种不同长度的项链。规定当且仅当两条项链通过旋转或者翻转后能重合在一起且对应珠子的颜色相同,则说两条项链相同。
旋转的情况,将项链顺时针旋转i格之后,循环节数是gcd(n, i)。旋转的置换一共有n种。
翻转的情况,如果n为奇数,考虑以某一个顶点为轴,一共有n种置换,每种置换的循环节数都是(n+1)/2。如果n为偶数,又可以分成以一对顶点为轴和以某相邻顶点的平分线为轴。以一对顶点为轴有n/2种置换,每种置换的循环节数都是n/2+1;另一种情况同样有n/2种置换,每种置换的循环节数为n/2。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#define maxn 200005
#define maxm 1005
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
int n, m;
ll qpow(ll a, ll x)
{
if(x == 0) return 1;
ll tmp = qpow(a, x/2);
ll ans = tmp*tmp;
if(x & 1) ans *= a;
return ans;
}
int gcd(int a, int b)
{
if(b == 0) return a;
return gcd(b, a % b);
}
int main()
{
while(scanf("%d%d", &m, &n))
{
if(n == 0 && m == 0) break;
ll ans = 0;
for(int i = 1;i <= n;i++)
ans += qpow(m, gcd(n, i));
if(n & 1)
ans += n*qpow(m, (n + 1)/2);
else
{
ans += (n/2)*qpow(m, n/2);
ans += (n/2)*qpow(m, 1 + n/2);
}
printf("%lld\n", ans/(2*n));
}
return 0;
}
poj2154 题意同上,只考虑旋转,n<=1e9。
只考虑旋转那么,显然无法枚举计算。考虑利用欧拉函数进行优化。
对于循环数为x=gcd(n, i),每个循环的长度就是n/x:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#define maxn 100005
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
int kase, n;
ll mod;
int eul(int t)
{
int res = t;
for(int i = 2;i*i <= t;i++)
{
if(t % i == 0)
{
res -= (res/i);
while(t % i == 0)
t /= i;
}
}
if(t > 1) res -= res/t;
return res;
}
ll qpow(int a, int x)
{
if(x == 0) return 1;
ll tmp = qpow(a, x/2);
ll ans = (tmp*tmp) % mod;
if(x & 1) ans = (ans*a) % mod;
return ans;
}
int main()
{
scanf("%d", &kase);
while(kase--)
{
scanf("%d%lld", &n, &mod);
ll ans = 0;
for(int i = 1;i*i <= n;i++)
{
if(n % i != 0) continue;
ans = (ans + 1LL*eul(n/i)*qpow(n, i - 1)) % mod;
if(i*i != n)
ans = (ans + 1LL*eul(i)*qpow(n, n/i - 1)) % mod;
}
printf("%lld\n", ans);
}
return 0;
}