一、咕咕东的奇遇
1.题目
咕咕东是个贪玩的孩子,有一天,他从上古遗迹中得到了一个神奇的圆环。这个圆环由字母表组成首尾相接的环,环上有一个指针,最初指向字母a。咕咕东每次可以顺时针或者逆时针旋转一格。例如,a顺时针旋转到z,逆时针旋转到b。咕咕东手里有一个字符串,但是他太笨了,所以他来请求你的帮助,问最少需要转多少次。
输入格式输入只有一行,是一个字符串。
输出格式输出最少要转的次数。
样例输入
zeus
样例输出
18
2.解题思路
minLen为计算两个字母a、b的距离。对于除a=b、(a+13)%26=b之外的其他情况,让b成为ascll码较大的那个字母,若b-a为正,则返回b-a,否则返回26-(b-a)。
3.c++代码
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int minLen(char a,char b)//从a到b最短路径
{
a=a-97;
b=b-97;
if(a==b)return 0;
if((a+13)%26==b)return 13;
if(a>b)//让a<b
{
int t;
t=a;
a=b;
b=t;
}
if(b>a)
{
if(b-a<13)return b-a;
else return 26-(b-a);
}
}
int main()
{
char ch[10001];
char c;
cin>>ch;
int ans=minLen('a',ch[0]);
for(int i=0;i<strlen(ch)-1;i++)//寻找strlen-1次
ans+=minLen(ch[i],ch[i+1]);
cout<<ans<<endl;
return 0;
}
二、B - 咕咕东想吃饭
1.题目
咕咕东考试周开始了,考试周一共有n天。他不想考试周这么累,于是打算每天都吃顿好的。他决定每天都吃生煎,咕咕东每天需要买ai个生煎。
但是生煎店为了刺激消费,只有两种购买方式:
①在某一天一次性买两个生煎。
②今天买一个生煎,同时为明天买一个生煎,店家会给一个券,第二天用券来拿。
没有其余的购买方式,这两种购买方式可以用无数次,但是咕咕东是个节俭的好孩子,他训练结束就走了,不允许训练结束时手里有券。咕咕东非常有钱,你不需要担心咕咕东没钱,但是咕咕东太笨了,他想问你他能否在考试周每天都能恰好买ai个生煎。
输入格式
输入两行,第一行输入一个正整数n(1<=n<=100000),表示考试周的天数。
第二行有n个数,第i个数ai(0<=ai<=10000)表示第i天咕咕东要买的生煎的数量。
输出格式
如果可以满足咕咕东奇怪的要求,输出"YES",如果不能满足,输出“NO”。(输出不带引号)
样例
样例输入1
4
1 2 1 2
样例输出1
YES
样例输入2
3
1 0 1
样例输出2
NO
2.解题思路
第一种购买方式是一次买偶数个生煎,第二种是第一天买奇数个生煎,同时第二天要买的生煎数减一。也就是若有一天的生煎数为奇数,则必须要选择第二种购买方式。
如此按天数循环,若该天需要买的生煎是偶数,可以选择第一种购买方式全部买完,直接进入第二天。若为奇数,则选择第二种方式购买一个生煎,剩下的偶数个生煎用第一种方式购买,同时第二天要买的生煎数减一。循环到最后一天,若生煎数为偶数,则成功,否则失败(因为选择第二种方式购买后手中有券存留)。
注意,该数据点每天的生煎数最大范围为10w,故采用while而非用数组存放每天的生煎数。
3.c++代码
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{
int n,x,t=0;
cin>>n;
while(n--)
{
cin>>x;
x-=t;
if(x%2==0&&n==0)
{
cout<<"YES"<<endl;
break;
}
else if(x%2==1&&n==0)
{
cout<<"NO"<<endl;
break;
}
if(x%2==0)
t=0;
else if(x%2==1)
t=1;
}
return 0;
}
三、C - 可怕的宇宙射线
1.题目
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着-种叫做苟狗的生物, 这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂n次,每次分裂后会在分裂方向前进a个单位长度。
现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生zjm那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击”。
样例输入
4
4 2 3 2
样例输出
39
2.解题思路
以第一次分裂的第一个点表示为二维坐标(0,1),结构体存储每个格的坐标。每次分裂都有两个方向,故可用递归实现。分裂后的走向有八种,可用0~7表示,并用set存储走过的方格,因为set可以自动去重复,所以可以不用考虑射线走到同一个格的情况,但是要重载<函数。递归时,将射线走过的方格放进set,并按照射线的方向分类讨论分裂后的方向。直到分裂次数到达N就返回。但是这样写完只能40分,剩下的数据点会超时。
又注意到在第六七次的分裂后,会有大量的在同一分裂层次、同一方向并处于同一点的情况,这时就不必再递归,因为后续分裂情形已发生过。这样就不会超时了,可AC。
3.c++代码
#include<iostream>
#include<map>
#include<set>
using namespace std;
struct coordinate
{
int x;
int y;
bool operator<(const coordinate& c)const
{
if(x!=c.x)return x<c.x;
else return y<c.y;
}
};
int splitLen[40];//每次分裂后还要前进的长度
int count=0;//答案
int n;//共分裂几次
set<coordinate> thisS;
bool bett[10][50][500][500]={false};
void s(coordinate thisCo,int dir,int num)
{
//coordinate co;
if(num==n)//截止条件
return;
if(bett[dir][num][thisCo.x][thisCo.y])
//判断在当下分裂次数、分裂方向、分裂坐标的情况是否已存在,若存在就无需进行分裂
return;
bett[dir][num][thisCo.x][thisCo.y]=true;
if(dir==0)//向上
{
int len=splitLen[num];
while(len--)
{
thisCo.y+=1;
thisS.insert(thisCo);
}
num++;
s(thisCo,1,num);
s(thisCo,7,num);
}
if(dir==1)
{
int len=splitLen[num];
while(len--)
{
thisCo.x+=1;thisCo.y+=1;
thisS.insert(thisCo);
}
num++;
s(thisCo,0,num);
s(thisCo,2,num);
}
if(dir==2)
{
int len=splitLen[num];
while(len--)
{
thisCo.x+=1;
thisS.insert(thisCo);
}
num++;
s(thisCo,1,num);
s(thisCo,3,num);
}
if(dir==3)
{
int len=splitLen[num];
while(len--)
{
thisCo.x+=1;thisCo.y-=1;
thisS.insert(thisCo);
}
num++;
s(thisCo,2,num);
s(thisCo,4,num);
}
if(dir==4)
{
int len=splitLen[num];
while(len--)
{
thisCo.y-=1;
thisS.insert(thisCo);
}
num++;
s(thisCo,3,num);
s(thisCo,5,num);
}
if(dir==5)
{
int len=splitLen[num];
while(len--)
{
thisCo.x-=1;thisCo.y-=1;
thisS.insert(thisCo);
}
num++;
s(thisCo,4,num);
s(thisCo,6,num);
}
if(dir==6)
{
int len=splitLen[num];
while(len--)
{
thisCo.x-=1;
thisS.insert(thisCo);
}
num++;
s(thisCo,5,num);
s(thisCo,7,num);
}
if(dir==7)
{
int len=splitLen[num];
while(len--)
{
thisCo.x-=1;thisCo.y+=1;
thisS.insert(thisCo);
}
num++;
s(thisCo,6,num);
s(thisCo,0,num);
}
}
int main()
{
int dir=0;//0~7表示向上顺时针方向的编号
cin>>n;
for(int i=0;i<n;i++)
cin>>splitLen[i];
coordinate thisCo;thisCo.x=0;thisCo.y=0;
s(thisCo,0,0);
cout<<thisS.size()<<endl;
return 0;
}