第一次CSP模拟 C题 可怕的宇宙射线

可怕的宇宙射线

题目:
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天 生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁 人的智商,进行降智打击! 宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的 左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂 次,每次分裂后会在分裂方向前进 个单位长度。 现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生 那么菜的水平,所以瑞神来请求你帮他计算出共有多 少个位置会被"降智打击"。

Input

输入第一行包含一个正整数 ,表示宇宙射线会分裂 次 第二行包含n个正整数 ,第 i个数 ai表示第 i次分裂的宇宙射线会在它原方向上继续走多少个单位长度。

Output

输出一个数 ,表示有多少个位置会被降智打击

Example

Input:
4
4 2 2 3
Output:
39

在这里插入图片描述在这里插入图片描述

我的解题思路:
这道题在模拟比赛的时候,我并没有完全做出来。比赛时,最开始想到了考虑对称性的问题,但是当时并没有推出公式,所以就是使用了dfs的方法,但是会超时。在赛后,对于对称性的深究,发现了规律。
假设起始点为(x,y),分裂后,右侧点为(x’,y’),可知左侧点坐标。
垂直射线分裂:(2x-x’,y’)
水平射线分裂:(x’,2y-y’)
与x轴正方向呈45度射线分裂:(x+y’-y,y+x’-x)
与x轴负方向呈45度射线分裂:(x+y-y’,x+y-x’)
这样就可以只计算右侧的分裂,然后再对称到左侧点。用set保存射线经过的点,这样set会自动去重,最后直接size()就可以得到经过的点数了。主要过程是,递归,在每一层的第一步判断是否到头,然后就进入下一个点,这样就可以从后往前进行整个过程。

我的总结:
在比赛的时候,尤其是遇到难题时,要先想明白题目要求,整理好思路,然后再写代码。
我的代码:

#include<cstdio>
#include<set>
using namespace std;

struct dott
{
	int x,y;
	bool operator<(const dott& D)const
	{
		return x!=D.x?x<D.x:y<D.y;
	}
};

int n,a[30];
set<dott> doo;
int opx[8]={0,1,1,1,0,-1,-1,-1},opy[8]={1,1,0,-1,-1,-1,0,1};


void dot(int ind,int x1,int y1,int op)
{
    if(ind==n) return;
    dot(ind+1,x1+opx[op]*a[ind],y1+opy[op]*a[ind],(op+1)%8);
    set<dott> t;
    for(auto &i:doo)
    {
    	if(op==0||op==4)
    	{
    		t.insert({2*x1-i.x,i.y});
		}
		else if(op==1||op==5){
			t.insert({x1+i.y-y1,y1+i.x-x1});
		}
		else if(op==2||op==6){
			t.insert({i.x,2*y1-i.y});
		}
		else{
			t.insert({x1+y1-i.y,x1+y1-i.x});
		}
	}
	doo.insert(t.begin(),t.end());
    for(int i=0;i<a[ind];i++)
    {
    	x1+=opx[op],y1+=opy[op];
		doo.insert({x1,y1});
    }
}

int main()
{
    scanf("%d",&n);
    for (int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    dot(0,0,0,0);
    printf("%d",doo.size());
    return 0;
}

发布了26 篇原创文章 · 获赞 0 · 访问量 449

猜你喜欢

转载自blog.csdn.net/qq_43738677/article/details/104885430
今日推荐