前面的废话不多说,直接切入正题:
为了简化这个问题,避免过于盲目的构造,我们需要考虑一下,能拼接出哪些基本块呢?
2种:2*3 长方形 和 n=2 的L型
不要看到样例给图是1、2、4就轻易猜想只有2^n才行,多多试试看嘛……
其实知道有这两种基本块,就很容易想到,n=6是可以构造的:直接18个长方形摆满就好了
看着手上有2*3,还有每边都是2的L型,一个容易想到的事情是:我可不可以在已知n=4的基础上,构造出n=6的呢?
答案:可以,在左下角用一个n=2的L型,其他位置用2*3的长方形铺设即可,如下图:
类似的(比较容易构造出来的),可以由n=6的L型得到n=8和n=10的L型:
(注意到,与n=6的情况有些差异,在左上角和右下角的2*3的长方形交界处)
(注意到,这个形态是最特别的,左上角、左下角、右下角都是n=2的L型,剩余空白用2*3的长方形填充)
之后你会发现,构造n=12、14、16的方法又是上面的循环……
为什么呢?
首先,这个L形是关于左下角与L型的右上角缺口的连线的轴对称图形,为了方便说明,我们只说明最上面和最左面的规律。
考虑扩展后的n,其n%3的情况:
n%3==0:最上面直接用2*3的长方形长边塞满(能被整除),对左面来说,剩下的长度为2*n-2,模3余1,刚好用一个n=2的L形来填充,剩下的空位用2*3的长方形塞满
n%3==2:最上面直接用2*3的长方形长边塞不满,余2,用2*3长方形的短边填充,对左面来说,剩下的长度为2*n-3,模3余1,还是用一个n=2的L形来填充,剩下的空位用2*3的长方形塞满n%3==1:最上面直接用2*3的长方形长边塞不满,余1,这次只能用n=2的L型放上去,余0,再用2*3的长方形填充,对左面来说,剩下的长度为2*n-4,模3余1,还是用一个n=2的L形来填充,剩下的空位用2*3的长方形塞满
好像,构造规律总结出来了?
显然,这些规律对n==1、3、5、7这些奇数也都适用!!
所以,这个问题没有impossible的情况,全部可构造!
只要在最内部填上n=1或n=2的L型,不停向外+2扩展即可。
帮人帮到底,送佛送到西。
这样难度的构造其实只要专门拉个人出去想,绝对想得出来的。(于是全场我埋头坑B,队友拼命搞别的题了)
实现呢?
首先,放上5种基本块的形态:2*3长方形的横向和纵向,还有n=2的L型的3种旋转(有一种在我们的构造方案里是没用的)。
之后写个函数,把基本块形态正确的画到结果的图纸上。
然后先写主函数,估算最中心位置,然后每次往外扩张2(留个函数名在那里,先不急)并调整绘制的左上角位置与n值,顺带写好输出。
最后,深呼吸,最麻烦的部分,往外扩张2的函数。
根据n%3的情况分类讨论。
对于放置L型方块,比较简单,确定位置画下去就行,不会平移。
对于2*3长方形,推荐预先在草稿纸上画上图,计算完初始偏移量,停止的边界条件(怕犯错,再写上每步的位移量),然后写到代码里。
最后,把n=1、2、3、4、5、6、7、8全部输进去,检查一下,没问题了,那就真的过了
代码如下:
#include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <math.h> #include <algorithm> using namespace std; typedef long long ll; const int shape[5][4][4]={{ {1,1,2,0}, {1,2,2,0}, {0,0,0,0}, {0,0,0,0} },{ {1,1,0,0}, {1,2,0,0}, {2,2,0,0}, {0,0,0,0} },{ {1,1,0,0}, {1,2,0,0}, {3,2,2,4}, {3,3,4,4} },{ {1,1,3,3}, {1,2,2,3}, {4,2,0,0}, {4,4,0,0} },{ {0,0,2,2}, {0,0,1,2}, {4,1,1,3}, {4,4,3,3} } }; int lastid; int mp[2010][2010]; void paintDown(int type,int fx,int sx,int sy){ int sid=fx; if(type==1)sid+=2; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ if(shape[sid][i][j]) mp[sx+i][sy+j]=lastid+shape[sid][i][j]; } } lastid+=(type==0?2:4); } void twoBigger(int sx,int sy,int len){ int px,py; if(len%3==0){ for(px=0,py=0;py<len;py+=3) paintDown(0,0,sx+px,sy+py); for(px=2*len-2,py=4;py<2*len-2;py+=3) paintDown(0,0,sx+px,sy+py); for(px=2,py=0;px<2*len-4;px+=3) paintDown(0,1,sx+px,sy+py); for(px=len,py=2*len-2;px<2*len;px+=3) paintDown(0,1,sx+px,sy+py); paintDown(1,0,sx+2*len-4,sy); }else if(len%3==1){ for(px=0,py=4;py<len;py+=3) paintDown(0,0,sx+px,sy+py); for(px=2*len-2,py=4;py<2*len-4;py+=3) paintDown(0,0,sx+px,sy+py); for(px=4,py=0;px<2*len-4;px+=3) paintDown(0,1,sx+px,sy+py); for(px=len,py=2*len-2;px<2*len-4;px+=3) paintDown(0,1,sx+px,sy+py); //printf("%d\n",lastid); paintDown(1,1,sx,sy); paintDown(1,0,sx+2*len-4,sy); paintDown(1,2,sx+2*len-4,sy+2*len-4); }else{ for(px=0,py=2;py<len;py+=3) paintDown(0,0,sx+px,sy+py); for(px=2*len-2,py=4;py<2*len;py+=3) paintDown(0,0,sx+px,sy+py); for(px=0,py=0;px<2*len-4;px+=3) paintDown(0,1,sx+px,sy+py); for(px=len,py=2*len-2;px<2*len-2;px+=3) paintDown(0,1,sx+px,sy+py); paintDown(1,0,sx+2*len-4,sy); } } int main(){ int n; while(~scanf("%d",&n)){ memset(mp,0,sizeof(mp)); int sx,sy,len; if(n&1){ sx=sy=n; mp[sx][sy]=mp[sx+1][sy]=mp[sx+1][sy+1]=1; lastid=1; len=1; }else{ lastid=0; sx=sy=n-1; paintDown(1,0,sx,sy); len=2; } while(len<n){ len+=2; sx-=2; sy-=2; twoBigger(sx,sy,len); } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ printf(j==1?"%d":" %d",mp[i][j]); } puts(""); } for(int i=n+1;i<=2*n;i++){ for(int j=1;j<=2*n;j++){ printf(j==1?"%d":" %d",mp[i][j]); } puts(""); } } return 0; }