置换(群论)

 最近研究了一下置换:
不感兴趣者可直接看结论,由于以下证明都是自己想出来的,转载请说明出处。

性质1:对于长度为n的置换T,T^k的循环个数为gcd(n,k)


因为当k|n,T可以分解成k个循环,每个循环都是k的同余类

gcd(n,k)=1,T不能分解,因为k*s%n=k*t%n等价于n|k(s-t),由此可以肯定n|(s-t),s!=t的情况下,s=n*h+t>n,也就是要形成循环必须跳n步以上,也就是循环的长度至少为n,而最大也只能为n,因此不能分解

其他情况k=gcd(n,k)*(k/gcd(n,k)),等价计算(T^gcd(n,k))^(k/gcd(n,k)),由于(k/gcd(n,k))|n,所以T^ gcd(n,k)分解成gcd(n,k)个循环,并且每个循环的长度为n/gcd(n,k),计算(T^ gcd(n,k))^(k/gcd(n,k))时可以独立计算T^ gcd(n,k)的每个循环的k/gcd(n,k)次幂,由于gcd(k/gcd(n,k), n/gcd(n,k))=1,那么每个循环均不能分解,最终就是gcd(n,k)个循环

 

性质2:对于长度为n的置换T,T^k为恒等置换的最小正整数kn

因为T错位为1,T^2错位为2,……,T^(n-1)错位为n-1,T^n错位为0

推论:对于含有若干循环的置换T, T^k为恒等置换的最小正整数k为所有循环的长度的最小公倍数


poj3270  使一个序列有序化的最小代价,考虑序列循环内部采用最小数交换,或者用整个序列最小值替换循环内最小值,然后进行循环内最小数交换,最后再把原先循环内交换出去的数交换回来。

具体参考这篇博客:http://www.cnblogs.com/DreamUp/archive/2010/08/17/1801700.html 

类似题目求最小交换次数 uva11077

当然此题求方案数,自然使用dp,具体见大白书。

#include
#include
#include
#define ull unsigned long long
using namespace std;

ull dp[30][30];
int main()
{
    int n,k;
    while(cin>>n>>k,n){
        memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++) dp[i][0]=1;
        for(int i=2;i<=n;i++)
            for(int j=1;j

poj1026 置换的k次幂 重载置换乘法,然后快速幂即可,其实可以做到线性,从循环角度考虑。

poj2369 置换群至少经过多少次幂后,可变成恒等置换,答案是所有循环长度的最小公倍数。

poj1721 置换开方,详见上面的博客链接。

poj3128 是否存在置换T,满足T^2等于给定的置换,首先对于长度为奇数的循环,乘幂为2,根据上面的性质1,循环不分裂,反过来说长度为奇数的循环开2次方不合并,并且根据一对一的关系,解总是存在的。对于长度为偶数的循环,乘幂为2,则会分裂成2个不相交的循环,而且是2的同余类,因此将两个偶循环交替组合即可合并。因此只要满足偶循环个数为偶数,则必然有解,否则无解。

poj3590 将n拆成若干个正整数,使lcm最大,这里可以使用dp,并且可以证明最优解必然拆成素因子的次幂形式。

可以这么看,若存在两个数不互质,那么其中一个数除掉gcd,不改变总的lcm,但使和减小,反过来说,将这部分减少的再重新分配下可能得到更优解。因此分解的数两两互质,再考虑另一种情况,其中一个数为a^p1*b^p2...的形式,其中a和b为质数,这显然不是最优,将这个数拆成a^p1+b^p2+...,同样不改变总的lcm,但又使和减小,也就是有可能获得更优解。

#include
#include
#include
#include
using namespace std;

int cnt[110],res[110],dp[110][110];
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
int lcm(int a,int b){
    return a/gcd(a,b)*b;
}
vector dv;
int main()
{
    int t,n;
    cin>>t;
    while(t--){
        cin>>n;
        memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++) dp[i][1]=i;
        for(int i=2;i<=n;i++)
            for(int j=2;j<=i;j++)
                for(int k=j-1;k


Polya定理

实际上是求每个置换的循环数,对每个置换,累加一个颜色数^循环数。这个关键是如何求每个置换的循环数,简单的手推即可,或者程序跑一个全排列。

hdu1812 这题初看不怎么好求循环数,我们来看一下旋转90度的情况,可以看到正方形的四个顶点转了一圈,也就是形成了一个循环节为4的循环,然后你可以在正方形中找到每个这样的循环节为4的循环,注意当n为奇数时,最中间的一个是不动的,单独形成一个循环。然后其他旋转类似,轴对称就比较简单。由于这题要爆long long,所以用java写吧。

import java.math.BigInteger;
import java.util.Scanner;


public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int n,c;
		Scanner cin = new Scanner(System.in);
		while(cin.hasNextInt()){
			n = cin.nextInt();
			c = cin.nextInt();
			BigInteger base = BigInteger.valueOf(c);
			BigInteger ans = BigInteger.ZERO;
			if((n&1)==0){
				ans = ans.add(base.pow(n*n/4).multiply(BigInteger.valueOf(2)));
				ans = ans.add(base.pow(n*n));
				ans = ans.add(base.pow(n*n/2).multiply(BigInteger.valueOf(3)));
				ans = ans.add(base.pow((n*n-n)/2+n).multiply(BigInteger.valueOf(2)));
			}
			else{
				ans = ans.add(base.pow(n*n/4+1).multiply(BigInteger.valueOf(2)));
				ans = ans.add(base.pow(n*n));
				ans = ans.add(base.pow(n*n/2+1));
				ans = ans.add(base.pow((n*n-n)/2+n).multiply(BigInteger.valueOf(4)));
			}
			System.out.println(ans.divide(BigInteger.valueOf(8)));
		}
	}

}
未完...


你可能感兴趣的:(组合数学)