poj 1286 Necklace of Beads
题目:http://poj.org/problem?id=1286
置换的第一题!
学习笔记:
置换
长为n的排列。其实是1~n到1~n的一个映射,值表示该位置对应之前的哪个位置。
置换的集合叫做置换群。
可用置换群来刻画题目中的(循环)同构。 //刻画的只是同构!所以并没有n!那么多个
(循环)不同构的方案数:每个置换下不动点个数的平均值
不动点:在该数组上操作一次这个置换,等于没操作,这样的数组称为该置换下的不动点。
(比如数组上每个位置的值都一样 之类的)
一个置换的不动点个数:2^(该置换的环的个数)——环内的点要染成相同的颜色,不同的环之间不相互影响 //那个2因题而异
(因为环是转到的位置,为了不动,颜色要一样)
一个长为n的环,每次顺时针转k步,这样的置换有多少个环? //即环的旋转同构的个数
k和n互质,则只有一个环。
考虑角度:下一步的落脚点是p*k%n。p*k可以遍历%n剩余系。
k和n不互质,可以遍历的是剩余系中gcd的倍数部分。所以为了遍历剩余系,需要gcd个环。
证明:k和n互质,p在0~n-1范围内不能遍历%n剩余系的话:
p1*k=p2*k(mod n) -> (p1-p2)*k=0(mod n)
因为k和n互质,所以k有逆元,可以同除k,得到p1-p2=0。
k和n不互质,令k0=k/gcd , n0=n/gcd,则p*k0可以遍历%n0的剩余系
乘上gcd后变成遍历n剩余系中gcd的倍数部分。
对于环有n(奇数)个点,共n条对称轴(每个点被踩一次),每个对称置换有(n-1)/2+1个环。(也就是(n+1)/2)
对于环有n(偶数)个点,共n条对称轴(踩在点上n/2个,踩在边上n/2个),踩在点上的有(n-2)/2+2个环(每个被踩的点自成一环),踩在边上的有n/2个环。
每个置换的不动点数是3^(环数)(因为能染三种颜色)。
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; ll n,ans,cnt; ll pw(ll x,int k) { ll ret=1;while(k){if(k&1)ret*=x;x*=x;k>>=1;}return ret; } ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} int main() { while(1) { scanf("%lld",&n);if(n==-1)return 0; if(!n){printf("0\n");continue;} ans=pw(3,n);cnt=2*n; for(int i=1;i<n;i++)ans+=pw(3,gcd(i,n)); if(n&1) ans+=pw(3,((n-1)/2+1))*n; else ans+=pw(3,n/2)*n/2+pw(3,n/2+1)*n/2; printf("%lld\n",ans/cnt); } }