第四周CSP模拟
A - 咕咕东的奇遇
-
题意:
有一个子母钟,从A到Z首尾相接,起点为A。输入一个字符串,输出子母钟要得到该字符串要走的最小步数。 -
输入输出:
Input
hzet
Output
31
-
解题思路:
简单的贪心算法,输入数据为string类型,按照字符依次读取,每次求出子母钟从当前位置到下一个位置的最短距离,即比较顺时针和逆时针转哪个步数更少,更新指针位置。 -
代码实现:
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
string a;
cin>>a;
int i=0,j=0,p=0;
int length=a.length(); //字符串长度
for(int k=0;k<length;k++)
{
p=a[k]-'a';
j=j+min(abs(p-i),26-abs(p-i));//求出较小的步数
i=p;
}
cout<<j<<endl;
return 0;
}
B - 咕咕东想吃饭
-
题意:考试周有n天,咕咕东在每天希望买a1,a2,a3…an个生煎。有两种购买方式,第一种是一次性买两个,第二种是只拿一个生煎并领一张券第二天来领另一个生煎。问能否在n天理每天买到a[i]个生煎。
-
输入输出:
第一行输入n天,第二行输入每天需要买的生煎a1到an。能买到输出YES,不能输出NO。
Input
4
1 2 1 2
Output
YES
-
解题思路:
本题也较为简单,有两种购买方式,如果是偶数则可以视为第一种,奇数可以视为第二种。偶数个则在当天就可以消费掉,而奇数个需要后面再购买一次奇数个才可以抵消。如:2,4可以用第一种购买方法,而1,2,1则是第一天买一个领一张券,第二天领取前一天的并再买一个领一张券,第三天再领取前一天的,观察得只需要有两天购买奇数个就可以抵消掉。
定义count为计数器,每次遇到购买数为奇数的计数器加一,保证在遇到购买数为0的天数之前和在结束之前count为偶数,该购买方案就可以成立。 -
代码实现:
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
int a[200000];
for(int i=0;i<n;i++)
cin>>a[i];
int count=0;
for(int j=0;j<n;j++)
{
if(a[j]==0)
{
if(count%2==1)
{
cout<<"NO"<<endl;
return 0;
}
else
count=0;
}
if(a[j]%2==1)
count=count+1;
}
if(count%2==0)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
return 0;
}
C - 可怕的宇宙射线
-
题意:神奇的宇宙射线,每走一段就会分裂到两个方向,分裂的方向分别为原方向向左和向右偏45度。该宇宙射线最多分裂三十次,每次分裂后走的距离不大于5,需要计算该射线最后覆盖的格子数。宇宙射线分裂规律如下图:
-
输入输出:
第一行输入分裂次数,第二行输入每次分裂走的距离。
Input
4
4 2 2 3
Output
39
-
解题思路:
刚开始看到这道题会有点懵逼,因为神奇的宇宙射线分裂的实在是太放肆了。不过仔细思考发现并不是没有规律可循,因为它分裂的规律是一定的,知道了它分裂的方向和要走的长度即可以推出它走过的格子数。同时射线每次分裂成两条,可以发现它的分裂数量按照层数指数增加,故可以想到bfs的方法。单纯的bfs不进行剪枝数据量指数增长复杂度过大,会直接爆栈。故想到进行剪枝,在分裂到一定的量之后会有很多方向重复,而同一层的前进步数又相同,故计算一次即可。考虑将原来的二维标记数组改为四维数组,分别记录分裂点的方向、层数以及横纵坐标,重复的点不再入队,如此一来时间复杂度会大大降低。
结构体node成员为横纵坐标、方向和层数,进行初始化,结构体transfer记录方向更加方便。从起始点开始记录坐标、方向和层数,入队,开始bfs。每次到达一个新的分裂点先判断该点是否已经被标记,若标记过则不再入队,变量ans记录到达方格数,若未标记ans加上相应的步数。最后输出ans即为到达的方格数。
-
代码实现:
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
int n;
int a[40];
struct node
{
int x;
int y;
int dir;
int level;
node(){}
node(int xx,int yy,int tt,int ll)
{
x=xx;
y=yy;
dir=tt;
level=ll;
}
};
struct transfer
{
int x1;
int y1;
int x2;
int y2;
transfer(){}
transfer(int aa,int bb,int cc,int dd)
{
x1=aa;y1=bb;x2=cc;y2=dd;
}
};
transfer op[10];
bool viss[510][510];
bool vis[35][510][510][8];
queue<node> q;
int ans=0;
void bfs()
{
int sx,sy;
sx=250;
sy=250;
int num=a[0];
while(num--)
{
sx+=0;
sy+=1;
viss[sx][sy]=1;
ans++;
}
q.push(node(sx,sy,0,1));
vis[1][sx][sy][0]=1;
while(!q.empty())
{
node before=q.front();
q.pop();
if(before.level>=n)
break;
int steps=a[before.level];
int dx1,dy1,dx2,dy2;
dx1=before.x;dy1=before.y;dx2=before.x;dy2=before.y;
while(steps--)
{
dx1+=op[before.dir].x1;
dy1+=op[before.dir].y1;
dx2+=op[before.dir].x2;
dy2+=op[before.dir].y2;
if(!viss[dx1][dy1])
{
viss[dx1][dy1]=1;
ans++;
}
if(!viss[dx2][dy2])
{
viss[dx2][dy2]=1;
ans++;
}
}
int op1=(before.dir+7)%8;
int op2=(before.dir+1)%8;
if(!vis[before.level+1][dx1][dy1][op1])
{
vis[before.level+1][dx1][dy1][op1]=1;
q.push(node(dx1,dy1,op1,before.level+1));
}
if(!vis[before.level+1][dx2][dy2][op2])
{
vis[before.level+1][dx2][dy2][op2]=1;
q.push(node(dx2,dy2,op2,before.level+1));
}
}
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(vis,0,sizeof(vis));
memset(viss,0,sizeof(viss));
op[0]=transfer(-1,1,1,1);
op[1]=transfer(0,1,1,0);
op[2]=transfer(1,1,1,-1);
op[3]=transfer(1,0,0,-1);
op[4]=transfer(1,-1,-1,-1);
op[5]=transfer(0,-1,-1,0);
op[6]=transfer(-1,-1,-1,1);
op[7]=transfer(-1,0,0,1);
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
bfs();
return 0;
}