A-咕咕东的奇遇
题目描述
咕咕东是个贪玩的孩子,有一天,他从上古遗迹中得到了一个神奇的圆环。这个圆环由字母表组成首尾相接的环,环上有一个指针,最初指向字母a。咕咕东每次可以顺时针或者逆时针旋转一格。例如,a顺时针旋转到z,逆时针旋转到b。咕咕东手里有一个字符串,但是他太笨了,所以他来请求你的帮助,问最少需要转多少次。
Input
输入只有一行,是一个字符串。
Outout
输出最少要转的次数。
Sample input
zeus
Sample output
18
解题思路
- 每次旋转到一个字母有顺时针、逆时针两种方法
- 每次的转法对下一次不影响,所以使每一次转的次数都最短即可
- 看两个点的ASC码差值的绝对值,小于一半(13)则“直接转”,大于一半(13)则从模(26)-差值的方向转。将每次转的次数累和即可。
完整代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
string a;
cin>>a;
int count=0;
int m;
int length=a.length();
for(int i=0;i<length;i++)
{ if(i==0)
{m=a[i]-'a';}
else
m=a[i]-a[i-1];
if(m<0)
m=-m;
if(m<=13)
count=count+m;
else
count=count+26-m;
}
cout<<count<<endl;
}
B-咕咕东想吃饭
题目描述
咕咕东考试周开始了,考试周一共有n天。他不想考试周这么累,于是打算每天都吃顿好的。他决定每天都吃生煎,咕咕东每天需要买a_iai个生煎。但是生煎店为了刺激消费,只有两种购买方式:①在某一天一次性买两个生煎。②今天买一个生煎,同时为明天买一个生煎,店家会给一个券,第二天用券来拿。没有其余的购买方式,这两种购买方式可以用无数次,但是咕咕东是个节俭的好孩子,他训练结束就走了,不允许训练结束时手里有券。咕咕东非常有钱,你不需要担心咕咕东没钱,但是咕咕东太笨了,他想问你他能否在考试周每天都能恰好买a_iai个生煎。
Input
输入两行,第一行输入一个正整数n(1<=n<=100000)(1<=n<=100000),表示考试周的天数。第二行有n个数,第i个数a_i(0<=a_i<=10000)ai(0<=ai<=10000)表示第i天咕咕东要买的生煎的数量。
Output
如果可以满足咕咕东奇怪的要求,输出"YES",如果不能满足,输出“NO”。(输出不带引号)
Sample input 1
4
1 2 1 2
Sample output 1
YES
Sample input 2
3
1 0 1
Sample ouput 2
NO
解题思路
- 手中券的情况仅两种:1张,0张,多的可以用方案1代替
- 只需要看最后一天有没有剩余券即可
- 每天储存上一天的剩余券数,通过判断(今天的生煎-昨天的余券)%2判断今天有没有剩余券,不断递归,直到最后一天买完生煎。判断有没有券剩余即可。
- 注意特殊值0:某一天为0的话则方案一二都无法满足,无法继续;
-注意YES,NO是全大写
完整代码
//券有效情况仅两种:1张,0张,多的可以用方案1代替
//看最后一天有没有剩余券
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
int a[100100];
for(int i=0;i<n;i++)
cin>>a[i];
bool use=false;
for(int i=0;i<n;i++)
{ if(a[i]==0)
{//一天不吃生煎,两种策略无法实现
cout<<"NO"<<endl;
return 0;
}
if(use==false)
{if(a[i]%2==1)
use=true;}
else
{if((a[i]-1)%2==0)
use=false;}
}
if(use==true)
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
}
C-可怕的宇宙射线
题目描述
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂 次,每次分裂后会在分裂方向前进ai个单位长度。现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生zjm那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"。
Iuput
输入第一行包含一个正整数 n(n<=30),表示宇宙射线会分裂n 次
第二行包含n个正整数a1,a2···an ,第ai 个数表示第 i次分裂的宇宙射线会在它原方向上继续走多少个单位长度
Output
输出一个数ans ,表示有多少个位置会被降智打击
Sample input
4
4 2 2 3
12
Sample output
39
1
解题思路
- 本题难在方向多变,一共8个方向,想不到用数组记录,通过加减取余联系的话会比较复杂。
- 用四维数组vis记录当前坐标(x,y),第t次分裂,方向。
- 用二维数组mark记录所有到达过的点,防止重复。
- 用二维数组dir记录当前行代表的方向的下一个点的x,y。(此方法比较难想)
- dfs不断往下遍历,分裂次数到了即不再向下遍历。每次到达的点判断一下之前是否到过,没到过则ans++。
注意事项
- 每次在本方向上前进的长度k是本方向两点间距离的k倍,不是绝对长度k(考试时没认真看图误以为绝对长度k,最后算一堆小数,无法判断是否落在整数坐标点上,从而失败)
- dfs时要判断当前位置是否已到达、是否需要继续往下遍历。
完整代码
#include<cstdio>
int ans=0;
int vis[330][330][31][8],mark[330][330],n,a[35];
//vis[x][y][第i次分裂][延伸方向]
//mark判断当前点是否到达过
int dir[8][2]=
{{1,0},//0代表右
{1,1},//1代表右上
{0,1},//2代表上
{-1,1},//3代表左上
{-1,0},//4代表左
{-1,-1},//5代表左下
{0,-1},//6代表下
{1,-1}//7 代表右下
}; //0到7刚好是逆时针走一圈,所以对每个方向,下一分裂方向为当前方向+1、当前方向+7,再分别对8取余
void dfs(int x,int y,int t,int d)
{
if(vis[x][y][t][d]==1)//当前位置到达过了
return;
vis[x][y][t][d]=1;//标记为到达
for(int i=1;i<=a[t];i++)//a[t]是长度
{x=x+dir[d][0];
y=y+dir[d][1];
if(mark[x][y]==0)//之前没加入这个点
{ans++;
mark[x][y]=1;}}
if(t<n)//还没遍历完
{dfs(x,y,t+1,(d+1)%8);
dfs(x,y,t+1,(d+7)%8);}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs(160,160,1,2);
printf("%d",ans);
}