zoukankan      html  css  js  c++  java
  • [luogu]P2561 [AHOI2002]黑白瓷砖

    题意

    用六边形瓷砖拼成一个三角形,第i行有i个小瓷砖,问本质不同的方案数有多少。
    两个方案本质不同指两个方案不能通过120度或者1270度旋转,或者通过对角线翻转变成另一种。

    题解

    第二次做(Burnside)引理的题目(其实是因为不会(Polya)

    这道题的置换群比较直观,每个操作都是一个置换。

    先对于旋转操作,发现所有的循环置换的循环节长度都为3,对于一个循环置换来说,显然想要构成不动点就必须参与置换的砖块颜色必须一样。
    我们考虑有多少个这样的循环节,可以递推处理。
    对于一个三角形,考虑最外一层,假如为(n)层,则有(n - 1)个循环节。
    消除最外层之后,里面有(g[n - 3])个循环节。
    (g[1] = 0, g[2] = 1, g[3] = 2)

    考虑完循环节之后发现三角形内部有一个特殊的点,也就是有可能中间有一个不会动的点,循环节长度为1.
    这个也可以递推解决。
    (f[1] = 1, f[2] = 0, f[3] = 0)
    (f[i] = f[i - 3])

    然后考虑翻转对称。
    对于一个翻转,对称线上的砖块可以任意取色,而不在对称线上的两边必须同色。
    可以计算出这样的不动点个数有(2^{frac{n + lfloor frac{n + 1}{2} floor}{2}})个。

    然后是单位元。
    显然有(2^{frac{n imes (n + 1)}{2}})个。

    根据(Burnside)引理,总的方案数为(2^ {frac{ 2^{frac{n imes (n + 1)}{2}} + 2^{frac{n + lfloor frac{n + 1}{2} floor}{2}} imes 3 + 2 ^ {g[n] + f[n]} imes 2}{6}})

    记得加上高精度。

    博客的公式编辑器好像有点问题,建议观察代码获得公式。

    
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <map>
    #include <cstring>
    #define int long long
    #define Mid ((l + r) >> 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    
    using namespace std;
    
    int read(){
    	char c; int num, f = 1;
    	while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
    	while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
    	return f * num;
    }
    struct bignum{
        int g[505];
        int l;
        void init() { l=0; memset(g,0,sizeof(g)); }
        void one() { init(); l=1; g[1]=1; }
        void jw(){ while(g[l+1]>0) { ++l; g[l+1]=g[l]/10; g[l]%=10; }  }
        void out() { for(int i=l;i>=1;i--) printf("%d",g[i]); printf("
    "); }
    };
    
    int n, g[50], f[50];
    bignum ans;
    bignum operator +(bignum a,bignum b){
        bignum c; c.init();
        c.l=max(a.l,b.l);
        for(int i=1;i<=c.l;i++){
    	    c.g[i]+=a.g[i]+b.g[i];
    	    c.g[i+1]+=c.g[i]/10;
    	    c.g[i]%=10;
    	}
    	c.jw();
    	return c;
    }
    
    bignum operator *(bignum a,bignum b){
        bignum c; 
    	c.init(); c.l=a.l+b.l-1;
        for(int i=1;i<=a.l;i++)
        for(int j=1;j<=b.l;j++)
        c.g[i+j-1]+=a.g[i]*b.g[j];
        
        for(int i=1;i<=c.l;i++){
    	    c.g[i+1]+=c.g[i]/10;
    	    c.g[i]%=10;
    	}
    	c.jw();
    	return c;
    }
    
    bignum operator /(bignum a,int b){
        for(int i=a.l;i>=1;i--){
    	    a.g[i-1]+=(a.g[i]%b)*10;
    	    a.g[i]/=b;
    	}
    	
    	while(a.l>1&&a.g[a.l]==0) --a.l;
    	return a;
    }
    
    bignum ksm(int y){
        bignum ret; ret.one();
        bignum x; x.one(); x.g[1]=2;
        
        while(y){
    	    if(y&1) ret=ret*x;
    	    y>>=1;
    	    x=x*x;
    	}
    	return ret;
    } 
    signed main()
    {
    	n = read();
    	f[1] = 1; f[4] = 1;
    	g[2] = 1; g[3] = 2; g[4] = 3;
    	for(int i = 5; i <= 20; i++) 
    		g[i] = g[i - 3] + i - 1,
    		f[i] = f[i - 3];
    	ans = ksm(g[n] + 1 + f[n]);
    	ans = ans + ksm((n * (n + 1) / 2 + (n + 1) / 2) / 2) + ksm((n * (n + 1) / 2 + (n + 1) / 2) / 2) + ksm((n * (n + 1) / 2 + (n + 1) / 2) / 2);
    	ans = ans + ksm((n * (n + 1) / 2));
    	ans = ans / 6; 
    	ans.out();
    	return 0;
    }
    
  • 相关阅读:
    C#综合揭秘——细说事务
    软件项目管理流程总结
    WCF揭秘——自定义绑定
    WCF揭秘——共享数据契约
    反流程升职记
    .NET基础篇——利用泛型与反射更新实体(ADO.NET Entity Framework)
    先睹为快:Visual Studio 11测试版已于2.29在微软官方网站正式发布
    .NET基础篇——分部类和分部方法
    C#综合揭秘——深入分析委托与事件
    .NET基础篇——反射的奥妙
  • 原文地址:https://www.cnblogs.com/onglublog/p/14478249.html
Copyright © 2011-2022 走看看