【CSP - M1】A - 咕咕东的奇遇、B - 咕咕东想吃饭、C - 可怕的宇宙射线

A - 咕咕东的奇遇

题目:

咕咕东是个贪玩的孩子,有一天,他从上古遗迹中得到了一个神奇的圆环。这个圆环由字母表组成首尾相接的环,环上有一个指针,最初指向字母a。咕咕东每次可以顺时针或者逆时针旋转一格。例如,a顺时针旋转到z,逆时针旋转到b。咕咕东手里有一个字符串,但是他太笨了,所以他来请求你的帮助,问最少需要转多少次。

Input

输入只有一行,是一个字符串。

Output

输出最少要转的次数。

Sample Input

zeus

Sample Output

18

思路做法:

模拟整个过程,26个字母中给定2个字母,计算两者之间的距离。由题意start初始化为‘a’,输入的字符串str,循环更新ans和start值。计算len=(str[i]+26-start)%26,若len>13(26的一半)则str[i]在start顺时针方向且不超过13个单位用str[i]减start,否则在逆时针方向用start减str[i],并且取余数。循环完的ans值即为解。

总结:

不是很难,但是实际测试时for循环里忘记初始i=0,于是自己电脑上能跑出正确结果来,平台上全错了,教训啊。

代码:

#include <iostream>
#include <string>
using namespace std;
int main(){
	string str;
	cin>>str;
	int res=0;
	char start='a';
	for(int i=0;i<str.length();i++){
		int len=(str[i]+26-start)%26;
		if(len<=13){
			res+=(str[i]-start+26)%26;
		}else{
			res+=(start-str[i]+26)%26;	
		}
		start=str[i];
	}
	cout<<res<<endl;
	return 0;
}

B - 咕咕东想吃饭

题目:

咕咕东考试周开始了,考试周一共有n天。他不想考试周这么累,于是打算每天都吃顿好的。他决定每天都吃生煎,咕咕东每天需要买a_i个生煎。但是生煎店为了刺激消费,只有两种购买方式:①在某一天一次性买两个生煎。②今天买一个生煎,同时为明天买一个生煎,店家会给一个券,第二天用券来拿。没有其余的购买方式,这两种购买方式可以用无数次,但是咕咕东是个节俭的好孩子,他训练结束就走了,不允许训练结束时手里有券。咕咕东非常有钱,你不需要担心咕咕东没钱,但是咕咕东太笨了,他想问你他能否在考试周每天都能恰好买a_i个生煎。

Input

输入两行,第一行输入一个正整数n(1<=n<=100000),表示考试周的天数。
第二行有n个数,第i个数a_i(0<=a_i<=10000)表示第i天咕咕东要买的生煎的数量。

Output

如果可以满足咕咕东奇怪的要求,输出"YES",如果不能满足,输出“NO”。(输出不带引号)

Sample Input

4
1 2 1 2

Sample Output

YES

Sample Input

3
1 0 1

Sample Output

NO

思路做法:

根据题目,一天里要不买2个,要不买1个,且劵的数量(cnt)加1,第二天用劵来换(劵同时减少)。
具体分为偶数和奇数,分别对应2种情况,若当天不买但是劵还有,应理解为不能满足。考试结束后,判断劵的数量,若不为0,不能满足。

总结:

实际写代码时感觉有一两种情况(如当天不买但是劵还有)是有些困惑的,然后根据样例和自己的理解写上了。

代码:

#include <iostream>
using namespace std;
const int N=100005;
int a[N];
int main(){
	int n,cnt=0,res=1;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
		if(a[i]==0){
			if(cnt) res=0;
		}else{
			if(cnt){
				a[i]-=cnt;
				cnt=0;
			}
			if(a[i]%2){
				cnt++;
			}
		}
	}
	if(cnt) res=0;
	cout<<(res?"YES":"NO")<<endl;
	return 0;
}

C - 可怕的宇宙射线

题目:

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

Input

输入第一行包含一个正整数n(n<=30),表示宇宙射线会分裂n次
第二行包含n个正整数a_1,a_2,……a_n,第i个数a_i(a_i<=5)表示第i次分裂的宇宙射线会在它原方向上继续走多少个单位长度。

Output

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

Sample Input

4
4 2 2 3

Sample Output

39

思路做法:

递归求解。一条线需要定义当前坐标(x,y),方向d,要前进的长度len(代码中用数组的索引),用for循环实现前进(还要判重,走过的位置不计入ans,具体用map记录)后,射线分裂(递归剪枝,考虑是否有完全重合的射线,具体用map记录)。需要用到的量有方向(方向代号即一个索引值),用常量数组dir记录不同方向的dx,dy,next_dir记录该方向的射线分裂后的两个方向。初始值为(0,0),方向代号为0,len为索引0,递归到达边界(len索引超了)即停止。全部完毕后,更新完的ans即为解。

总结:

测试时想到的是bfs,还过了4个点,但是复杂度太高,后来优化很长时间也跑不出来,索性重写,并用dfs很快实现,为了map用到Point和Line两个结构体并重载小于号。

代码:

#include <iostream>
#include <map>
using namespace std;
struct Point{
	int x, y;
	Point(int _x, int _y):x(_x), y(_y){}
	bool operator<(const Point& p) const{
		if(x!=p.x) return x<p.x;
		return y<p.y;
	}
};
struct Line{
	int x, y, d, len;
	Line(int _x, int _y, int _d, int _len)
		:x(_x), y(_y), d(_d), len(_len){}
	bool operator<(const Line& l) const{
		if(x!=l.x) return x<l.x;
		if(y!=l.y) return y<l.y;
		if(d!=l.d) return d<l.d;
		return len<l.len;
	}
};
const int N = 35;
int a[N], ans=0, n;
map<Point, bool> isFound;
map<Line, bool> isSame;
const int dir[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
const int next_dir[8][2]={{1,7},{2,0},{3,1},{4,2},{5,3},{6,4},{7,5},{0,6}};

void dfs(int x, int y, int d, int len){
	if(len==n) return;
	if(isSame[Line(x, y, d, len)]) return;
	isSame[Line(x, y, d, len)]=1;
	int dx=dir[d][0], dy=dir[d][1];
	for(int i=0; i<a[len]; ++i){
		x+=dx; y+=dy;
		if(!isFound[Point(x, y)]){
			isFound[Point(x, y)]=1;
			ans++;
		}
	}
	dfs(x, y, next_dir[d][0], len+1);
	dfs(x, y, next_dir[d][1], len+1);
}

int main(){
	cin>>n;
	for(int i=0; i<n; ++i) cin>>a[i];
	dfs(0,0,0,0);
	cout<<ans<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

容嬷嬷当年一枝花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值