【hihocoder1257 2015北京赛区I】【构造 从公式入手】Snake Carpet 构造矩阵使得恰好容纳1~n个拐拐蛇行图案

#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
const int dy[2][4]={0,1,0,1,  1,0,-1,0};
const int dx[2][4]={1,0,-1,0,  0,1,0,1};
int n,H,W;
const int N=1005;
vector<pair<int,int> >a[N];
int b[N][N];
void push(int w,int y,int x)
{
    a[w].push_back(MP(y,x));
    b[y][x]=w;
}
void listfill(int y,int x,int w1,int w2)
{
    int size1=w1;
    int size2=w2;
    int d=0;
    while(size1--)
    {
        push(w1,y,x);
        y+=dy[0][d];
        x+=dx[0][d];
        d=(d+1)%4;
    }
    while(size2--)
    {
        push(w2,y,x);
        y+=dy[0][d];
        x+=dx[0][d];
        d=(d+1)%4;
    }
}
void linefill(int y,int x,int w1,int w2)
{
    int size1=w1;
    int size2=w2;
    int d=0;
    while(size1--)
    {
        push(w1,y,x);
        y+=dy[1][d];
        x+=dx[1][d];
        d=(d+1)%4;
    }
    while(size2--)
    {
        push(w2,y,x);
        y+=dy[1][d];
        x+=dx[1][d];
        d=(d+1)%4;
    }
}
//用所以奇数画正方形
void square(int y,int x,int top)
{
    for(int o=top;o>=1;o-=2)
    {
        ++y;
        ++x;
        int d=o/2;
        int yy=y+d;
        int xx=x+d;
        for(int i=yy;i>=y;i--)push(o,i,x);
        for(int i=x+1;i<=xx;i++)push(o,y,i);
    }
}
//用所有偶数画矩形
void rectangle(int h,int w,int top)
{
	if(h&1)
	{
		int u=top;
		int v=h+h-u;
		int x=1;
		while(u>v)
		{
			listfill(1,x,u,v);
			u-=2;
			v+=2;
			x+=2;
		}
	}
	else
	{
		int u=top;
		int v=w+w-u;
		int y=1;
		while(u>v)
		{
			linefill(y,1,u,v);
			u-=2;
			v+=2;
			y+=2;
		}
	}
}
void odd()
{
    H=(n+1)/2;
	W=n;
    int mv=n;
	int h=H;
	int w=W-(mv+1)/2;
	square(0,w,mv);
	rectangle(h,w,n-1);
}
void even()
{
    H=n/2;
	W=n+1;
    int mv=n-1;
	int h=H;
	int w=W-(mv+1)/2;
	square(0,w,mv);
	rectangle(h,w,n);
}
void printmap()
{
    for(int i=1;i<=H;i++)
    {
        for(int j=1;j<=W;j++)printf("%d ",b[i][j]);
        puts("");
    }
}
void print()
{
    printf("%d %d\n",H,W);
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<i;j++)printf("%d %d ",a[i][j].first,a[i][j].second);
        puts("");
    }
    //printmap();
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)a[i].clear();
        if(n&1)odd();
        else even();
        print();
    }
    return 0;
}
/*
【trick&&吐槽】
比赛的时候不要太悠闲了,不给自己的压力很多时候造成的恶果是,悲惨地只恰好差一分钟AC TwT

【题意】
给你一个n([1,500]),表示有n条蛇,蛇的身长从1到n,每条蛇所占的格子数也恰好等于其身长。
我们希望把这n条蛇,不交叉不溢出地都放到一个h*w的矩形中。(也就是说h*w=(1+n)*n/2)
并且使得:
对于身长为奇数的蛇(1除外),其扭曲的次数恰好为奇数;
对于身长为偶数的蛇(2除外),其扭曲的次数恰好为偶数。
让你构造出其方案,并按照身长从1~n,依次输出所有蛇。对于每条蛇,从头到尾输出其u偶在位置。

【类型】
构造

【分析】
首先,我们要分析这个矩形的形状,矩形的形状是h*w的话,h和w必定是其面积和的因子。
于是我每次想要枚举出最小的满足这个要求的h,然后再进行构造,然后就踏上了悲惨之路。
一个比较优秀的姿势是什么呢?
就是——既然h*w=(1+n)*n/2,我们就从这个公式入手!
所以,如果n为奇数,那我们就有因子{(1+n)/2和n};
	  如果n为偶数,那我们就有因子{n/2和(1+n)}。
然后,我们观察到,不论n为奇数还是偶数,对于所有的奇数,我们都是可以这么安排的——
1357
3357
5557
7777
我们发现,当n为奇数时,所有的奇数,恰好可以构成一个(n+1)/2的正方形
		  当n为偶数时,所有的奇数,恰好可以构成一个(n-1+1)/2=n/2的正方形
于是,我们可以剔除这个正方形。

然后,对于n为奇数,目前的矩形就是(n+1)/2 * (n-1)/2
	  对于n为偶数,目前的矩形就是n/2 * (n+2)/2

然后我们此时剩下的全部都是偶数
对于n%4==1,(n+1)/2 * (n-1)/2	可以用(n-1,2),(n-3,4)这样凑,形成的对数恰好是(n-1)/4对,每对的和恰好是n+1
对于n%4==2,n/2 * (n+2)/2		可以用(n)(n-2,2),(n-4,4)这样凑,形成的对数恰好是(n+2)/4对,每对的和恰好是n
对于n%4==3,(n+1)/2 * (n-1)/2	可以用(n-1)(n-3,2),(n-5,4)这样凑,形成的对数恰好是(n+1)/4对,每对的和恰好是n-1
对于n%4==0,n/2 * (n+2)/2		可以用(n,2)(n-2,4),(n-4,6)这样凑,形成的对数恰好是n/4对,每对的和恰好是(n+2)

而()中的每个数或每一对,能拐就拐,于是就都很容易就在2*d的格子中构造出解。于是就可以AC啦。
这个可以分开写,也可以归纳写,总之我们就可以这样AC啦~啦啦啦啦~

【时间复杂度&&优化】
O((n+1)*n/2)

*/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值