A - 咕咕东的奇遇
咕咕东是个贪玩的孩子,有一天,他从上古遗迹中得到了一个神奇的圆环。这个圆环由字母表组成首尾相接的环,环上有一个指针,最初指向字母a。咕咕东每次可以顺时针或者逆时针旋转一格。例如,a顺时针旋转到z,逆时针旋转到b。咕咕东手里有一个字符串,但是他太笨了,所以他来请求你的帮助,问最少需要转多少次。
Input
输入只有一行,是一个字符串。
Output
输出最少要转的次数。
Example Input
zeus
Example Output
18
Notes
数据点 字符串长度
1,2 小于等于10
3,4,5 小于等于100
6,7,8,9,10 小于等于10000
题意:
给出一个字符串,计算转出这个字符串最少需要转多少次。
分析:
26个字母围成一个圈,每次转动时,最多只能是13次,只需要求出顺时针或者逆时针转动时的最小值,每次转动结束后需要记住停在哪一个字母,遍历字符串即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<string>
#include<string.h>
#include<algorithm>
using namespace std;
char x[10010];
int main()
{
scanf("%s",x);
int m=strlen(x);
int now=0;
int ans=0;
int t,min,a,b;
for(int i=0;i<m;i++)
{
t=x[i]-'a';
a=abs(t-now);
b=26-abs(t-now);
if(a<=b)
min=a;
else
min=b;
ans+=min;
now=t;
}
printf("%d",ans);
return 0;
}
B - 咕咕东想吃饭
咕咕东考试周开始了,考试周一共有n天。他不想考试周这么累,于是打算每天都吃顿好的。他决定每天都吃生煎,咕咕东每天需要买a[i]个生煎。但是生煎店为了刺激消费,只有两种购买方式:
①在某一天一次性买两个生煎。
②今天买一个生煎,同时为明天买一个生煎,店家会给一个券,第二天用券来拿。
没有其余的购买方式,这两种购买方式可以用无数次,但是咕咕东是个节俭的好孩子,他训练结束就走了,不允许训练结束时手里有券。咕咕东非常有钱,你不需要担心咕咕东没钱,但是咕咕东太笨了,他想问你他能否在考试周每天都能恰好买a[i]个生煎。
Input
输入两行,第一行输入一个正整数n(1<=n<=100000)(1<=n<=100000)(1<=n<=100000),表示考试周的天数。
第二行有n个数,第i个数ai(0<=ai<=10000)a_i(0<=a_i<=10000)ai(0<=ai<=10000)表示第i天咕咕东要买的生煎的数量。
Output
如果可以满足咕咕东奇怪的要求,输出"YES",如果不能满足,输出“NO”。(输出不带引号)
Example Input
4
1 2 1 2
Example Output
YES
Notes
数据点 n(上限) a[i](上限)
1,2 10 10
3,4,5 1000 10
6,7 10 10000
8,9,10 100000 10000
题意:
给出两钟消费方式,再给出一个数组,试问能不能用所给的消费方式组成所给的数组。
分析:
首先我们来分析一下这两种消费方式,第一种一天买两个,第二种相当于连续两天各买一个,应该首先选择第一种方式,因为其对于后续没有影响,当某一天为奇数时,只能选择第二种方式,但这种方式需要对下一天的数组进行操作,对每个a[i],每次操作相当于减去一个数,当a[i]中的任何一个(包括a[n])变为负数时,则输出“NO”,否则输出“YES”。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
int* a = new int[n + 1];
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
a[n] = 0;
for (int i = 0; i < n; i++)
{
if (a[i] < 0)
{
cout << "NO" << endl;
return 0;
}
if (a[i] % 2 == 1)
{
a[i] = 0;
a[i + 1]--;
}
}
if (a[n] < 0)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
}
return 0;
}
C-可怕的宇宙射线
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂 次,每次分裂后会在分裂方向前进ai个单位长度。现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生zjm那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"。
Input
输入第一行包含一个正整数 n(n<=30),表示宇宙射线会分裂n 次
第二行包含n个正整数a1,a2···an ,第ai (ai<=5)个数表示第 i次分裂的宇宙射线会在它原方向上继续走多少个单位长度
Output
输出一个数ans ,表示有多少个位置会被降智打击
Example Input
4
4 2 2 3
Example Output
39
Notes
数据点 n
10% <=10
40% <=20
100% <=30
题意:
一束会分裂的宇宙射线,每次分裂成两股,分裂n次后,计算出射线所覆盖的范围。
分析:
这道题做了好久,每次都是时间复杂度太高,后来发现还是没有弄清楚问题的本质,直接就开始胡乱dfs,后来听助教讲解过之后,才发现还是没有掌握做这一类题目的方法,没有理清楚思路就开始动手,后来不断拆东墙补西墙。
射线的最大活动范围是一个300*300的正方形,所以可以使用一个bool型的数组来对每一个点进行标记,射线一共有八个前进的方向,也可以用定值的数组来控制分裂的次序,同一个点在同一个方向,并且在同一次分裂时就可以进行剪枝,并且不会影响后续的分裂。防止重复dfs造成超时。还有一个细节问题,刚开始将原点定在了(0,0),没有考虑到这样会造成产生负值,后来定为(150,150)才解决问题。
代码如下:
#include<iostream>
using namespace std;
//控制八个方向
int dx[8] = { 0,1,1,1,0,-1,-1,-1 };
int dy[8] = { 1,1,0,-1,-1,-1,0,1 };
//每个顶点的标记
bool point[300][300][30][8] = { false };
//空间中每个点的标记
bool label[300][300] = { false };
int a[30] = { 0 };
int n = 0;
int ans = 0;
void dfs(int x, int y, int m, int d)
{
if (m == n)
return;
if (!point[x][y][m][d])
{//这个点没有分裂过,开始分裂
point[x][y][m][d] = true;
for (int i = 1; i <= a[m]; i++)
{
if (!label[x + dx[d] * i][y + dy[d] * i])
{
label[x + dx[d] * i][y + dy[d] * i] = true;
ans++;
}
}
dfs(x + dx[d] * a[m], y + dy[d] * a[m], m + 1, (d + 1) % 8);//继续右侧分裂
dfs(x + dx[d] * a[m], y + dy[d] * a[m], m + 1, (d + 7) % 8);//继续左侧分裂
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
dfs(150, 150, 0, 0);
cout << ans;
return 0;
}