返回顶部

polya置换

UVA10294

POLYA定理的基本应用

题意:
有n个珠子围成的环,有t种颜色可以染这些珠子;
如果这个环可以旋转有几种办法;
如果这个环可以旋转,且可以翻转,有几种办法;

参考博客

刘汝佳的分析:

       等价类计数问题。一共有两种置换,选择以及翻转。项链只有第一种置换,手镯则有两种置换。设所有珠子按逆时针编号0~n-1。

       旋转置换:如果逆时针旋转i颗珠子的间距,则珠子0、i、2i、…构成一个循环。这个循环有n/gcd(i,n)个元素。根据对称性,所有循环的长度相同,因此一共有n/(n/gcd(i,n)) = gcd(i,n)个循环。该置换的不动点数为t^(gcd(i,n))。所有置换的不动点总数为a = sum{t^gcd(i,n) | i = 0,1,…,n - 1}。

       翻转置换:分情况讨论。当n是奇数时,对称轴有n条,每条对称轴形成(n-1)/2个长为2的循环以及1个长为1的循环,即(n+1)/2个循环。这些置换的不动点总数是b=nt^((n+1)/2)。

当n是偶数时,有两种对称轴。穿过珠子的对称轴有n/2条,各形成n/2-1个长为2的循环,还形成两个长为1的循环;不穿过珠子的对称轴有n/2条,各形成n/2个长为2的循环。这些置换的不动点总数是b = n / 2 * (t ^ (n / 2 + 1) + t ^ (n / 2))。

       根据Polya定理,项链总数为a/n,手镯总数是(a + b) / (2n)。

 1 #include<bits/stdc++.h>
 2 #define mp make_pair
 3 #define pb push_back
 4 #define first fi
 5 #define second se
 6 #define pw(x) (1ll << (x))
 7 #define sz(x) ((int)(x).size())
 8 #define all(x) (x).begin(),(x).end()
 9 #define rep(i,l,r) for(int i=(l);i<(r);i++)
10 #define per(i,r,l) for(int i=(r);i>=(l);i--)
11 #define FOR(i,l,r) for(int i=(l);i<=(r);i++)
12 #define eps 1e-9
13 #define PIE acos(-1)
14 #define cl(a,b) memset(a,b,sizeof(a))
15 #define fastio ios::sync_with_stdio(false);cin.tie(0);
16 #define lson l , mid , ls
17 #define rson mid + 1 , r , rs
18 #define ls (rt<<1)
19 #define rs (ls|1)
20 #define INF 0x3f3f3f3f
21 #define LINF 0x3f3f3f3f3f3f3f3f
22 #define freopen freopen("in.txt","r",stdin);
23 #define cfin ifstream cin("in.txt");
24 #define lowbit(x) (x&(-x))
25 #define sqr(a) a*a
26 #define ll long long
27 #define ull unsigned long long
28 #define vi vector<int>
29 #define pii pair<int, int>
30 #define dd(x) cout << #x << " = " << (x) << ", "
31 #define de(x) cout << #x << " = " << (x) << "\n"
32 #define endl "\n"
33 using namespace std;
34 //**********************************
35 int n,t;
36 ll f[17];
37 //**********************************
38 void get(int n)
39 {
40     f[0]=1;
41     FOR(i,1,n)f[i]=f[i-1]*t;
42 }
43 inline int gcd(int a,int b)
44 {
45     return b==0?a:gcd(b,a%b);
46 }
47 //**********************************
48 int main()
49 {
50     while(~scanf("%d%d",&n,&t)){
51         get(n);
52         ll a=0,b=0;
53         rep(i,0,n)a+=f[gcd(i,n)];
54         if(n%2==1)b=n*(f[(n+1)/2]);
55         else b=n/2*(f[n/2+1]+f[n/2]);
56         printf("%lld %lld\n",a/n,(a+b)/2/n);
57     }
58     return 0;
59 }
View Code

 

posted @ 2018-09-18 20:35  牛奶加咖啡~  阅读(208)  评论(0编辑  收藏  举报