A - 咕咕东的奇遇
题意
咕咕东是个贪玩的孩子,有一天,他从上古遗迹中得到了一个神奇的圆环。这个圆环由字母表组成首尾相接的环,环上有一个指针,最初指向字母a。咕咕东每次可以顺时针或者逆时针旋转一格。例如,a顺时针旋转到z,逆时针旋转到b。咕咕东手里有一个字符串,但是他太笨了,所以他来请求你的帮助,问最少需要转多少次。
解题思路
对于给定的字符串,计算圆环转出字符串所需次数。
只需遍历字符串计算当前的字母顺时针和逆时针转到下一个字母所需的转数,取最小值加入ans中。
代码
#include<bits/stdc++.h>
using namespace std;
char str[20005];
int main(){
cin>>str;
int cur = 0;
int ans = 0;
int len = strlen(str);
for(int i = 0; i < len;i++){
int now = str[i] - 'a';
int shun = 26 - ((now - cur)+26)%26;
int ni = ((now - cur)+26)%26;
ans += min(ni,shun);
cur = now;
}
cout << ans << endl;
return 0;
}
B - 咕咕东想吃饭
题意
咕咕东考试周开始了,考试周一共有n天。他不想考试周这么累,于是打算每天都吃顿好的。他决定每天都吃生煎,咕咕东每天需要买 a i a_i ai 个生煎。但是生煎店为了刺激消费,只有两种购买方式:①在某一天一次性买两个生煎。②今天买一个生煎,同时为明天买一个生煎,店家会给一个券,第二天用券来拿。没有其余的购买方式,这两种购买方式可以用无数次,但是咕咕东是个节俭的好孩子,他训练结束就走了,不允许训练结束时手里有券。咕咕东非常有钱,你不需要担心咕咕东没钱,但是咕咕东太笨了,他想问你他能否在考试周每天都能恰好买 a i a_i ai个生煎。
解题思路
对于咕咕东的两种买法,如果咕咕东按方案2买两次,就相当于按方案1分别在两天买一次,所以无论按方案2买多少次有区别的只有1次。故对于每一天,都先按方案1买,直到剩下1个再按方案2买。咕咕东不能恰好买到的情况有:
- 当前这天按方案1买完还剩1个生煎,但是下一天需要的生煎数为0.
- 当前这天按方案1买完还剩1个生煎,且当前是最后一天。
反思
在课上做这题时我选择了另一种做法,不用存储咕咕东每一天需要的生煎数量,但是考虑起来更加复杂,容易遗漏,耗费了不必要的时间,最后还WA了两个点TAT,但实际上本题数据量小,空间完全够用,不必要节省那么点的空间而耗费精力。
代码
#include<bits/stdc++.h>
int a[100005];
using namespace std;
int main(){
int n;
bool flag = true;
cin>>n;
for(int i=0;i<n;i++){
cin >> a[i];
}
for(int i=0;i<n;i++){
a[i] %= 2;
if(a[i] && i!=n-1){
if(a[i+1] == 0) flag = false;
else a[i+1]--;
}else if(a[i] && i == n-1){
flag = false;
}
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
C - 可怕的宇宙射线
题意
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂
n
n
n次,每次分裂后会在分裂方向前进
a
i
a_i
ai个单位长度。
现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生
z
j
m
zjm
zjm那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"
解题思路
- 从第一个点开始进行dfs模拟射线的前进与分裂,同时使用变量 n o d e s [ i ] [ j ] [ k ] nodes[i][j][k] nodes[i][j][k]来记录dfs过程中经过坐标 ( i , j ) (i,j) (i,j)且为第 k k k次分裂的射线经过时状态(因为没记录k而WA了好多次QwQ)。
- 在dfs时,对于一个未结束的射线,直接将线段中间的坐标置为已访问,只对首尾进行dfs,而不用一个一个坐标加入递归,能够节省不少时间。
- 对于射线分裂的判断是有规律可循的,当射线x方向无速度时,射线y方向速度不变,向左右(即x = ±1)分裂,当y方向无速度时同理向上下(y = ± 1)分裂,剩余斜射的情况,会分别向x和y方向分裂,即x方向不变,y方向置为0;y方向不变,x方向置为0.
代码
#include<bits/stdc++.h>
using namespace std;
struct Node{
int x,y,last;
int dx,dy;
bool operator==(const Node& other) const{
if(dx == other.dx && dy == other.dy && last == other.last)
return true;
else
return false;
}
};
int ans = 0;
bool flag[305][305] = {0};
Node nodes[305][305][35] = {0};
int a[35];
int n;
void dfs(int i, Node node){
if(flag[node.x][node.y] == false){
flag[node.x][node.y] = true;
nodes[node.x][node.y][i] = node;
}else{
if(nodes[node.x][node.y][i] == node)
return;
nodes[node.x][node.y][i] = node;
}
while(--node.last){
node.x+=node.dx;
node.y+=node.dy;
flag[node.x][node.y] = true;
}
if(i+1 == n) return;
node.last = a[i+1];
Node temp = node;
if(node.dx == 0){
temp.dx=1;
temp.x = node.x + 1;
temp.y = node.y + node.dy;
dfs(i+1,temp);
temp.x = node.x - 1;
temp.y = node.y + node.dy;
temp.dx=-1;
dfs(i+1,temp);
}else if(node.dy == 0){
temp.dy = 1;
temp.y = node.y + 1;
temp.x = node.x + node.dx;
dfs(i+1,temp);
temp.dy = -1;
temp.y = node.y - 1;
temp.x = node.x + node.dx;
dfs(i+1,temp);
}else{
temp.dx = 0;
temp.y = node.y+node.dy;
dfs(i+1,temp);
temp.dx = node.dx;
temp.dy = 0;
temp.y = node.y;
temp.x = node.x + node.dx;
dfs(i+1,temp);
}
}
int main(){
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
}
Node node;
node.x = 150, node.y = 150, node.dx = 0, node.dy = 1, node.last = a[0];
dfs(0,node);
for(int i = 0; i < 305; i++)
for(int j = 0; j < 305; j++)
if(flag[i][j])
ans++;
cout << ans << endl;
return 0;
}