码迷,mamicode.com
首页 > 其他好文 > 详细

[luogu]P2561 [AHOI2002]黑白瓷砖

时间:2021-03-04 13:26:48      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:lang   置换   clu   三角形   oid   获得   signed   sign   ace   

题意

用六边形瓷砖拼成一个三角形,第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} \rfloor}{2}}\)个。

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

根据\(Burnside\)引理,总的方案数为\(2^ {\frac{ 2^{\frac{n \times (n + 1)}{2}} + 2^{\frac{n + \lfloor \frac{n + 1}{2} \rfloor}{2}} \times 3 + 2 ^ {g[n] + f[n]} \times 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("\n"); }
};

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;
}

[luogu]P2561 [AHOI2002]黑白瓷砖

标签:lang   置换   clu   三角形   oid   获得   signed   sign   ace   

原文地址:https://www.cnblogs.com/onglublog/p/14478249.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!