您的位置:首页 > 其它

【第六篇blog】第三次模拟赛的反思与解析

2017-12-16 23:57 197 查看

模拟赛题目来自自行设计

严禁转载

——————————————————————我是更新提示分割线———————————————————————

<第一次更新>使用完整题目,切勿转载。

—————————————————————我是华丽丽的正文分割线——————————————————————

这次考试时间充裕,但仍考不出很好的成绩,题目有一定的代码量,有许多细节需要仔细辩题。

T1

1.越越的交通指挥系统

(traffic.pas/c/cpp)

【问题描述】

2027年,越越从北大毕业,想为家乡诸暨做点贡献,越越的家乡诸暨市有很多交通路口,其中有26个交通路口在上下班高峰期总是堵车,严重影响市民的出行。于是交通管理部门研制了一批机器人交通警察,用它们来专门指挥这26个交通路口,但需要一个自动化指挥系统来指挥机器人的运作。这个任务交给了越越,越越的设计如下。

分别用大写英文字母A,B,C,…Z表示这26个路口,并按如下的规则派出这些机器人到交通路口协助指挥交通:

1、每次派出两名机器人。

2、当两名机器人的名字中存在一个相同的字母时,这两名机器人便到对应的交通路口指挥交通;有多个字母相同时,两名机器人需要按字母的字典顺序到这些路口巡逻。

3、当两名机器人的名字中不存在相同的字母时,交警部门的派出指令无效(wuxiao)。

假设这些机器人的名字全由大写字母组成,请你编一个程序,帮越越完成这个交通指挥系统。

【输入】

第一行:输入第一个机器人的名字(长度不超过250);

第二行:输入第二个机器人的名字(长度不超过250)。

【输出】

1、当不能排除机器人时,在第一行输出“WuXiao”.

2、当两名机器人在路口上指挥交通时,在第一行输出“ZhiHui”,在第二行输出路口编号。

3、当两名机器人在路口上巡逻时,在第一行输出“XLuo”,第二行输出巡逻的路口数,第三行输出巡逻线路。

【输入输出样例1】

traffic.in traffic.out

OPEN

CLOSE XLuo

2

E-O

【输入输出样例2】

traffic.in traffic.out

EPSON

SENPUM XLuo

4

E-N-P-S

【数据范围】

pass

题意:对字符串进行扫描分类,并进行不同的模拟。

解析:对于题意的的分类操作,一定要注意细节,读懂题意的每一个操作以及输出格式。对于部分没有样例的材料更要加以辨析。重在题意理解和细节的发现。

思路:对字符串进行扫描,用返回值变量套if语句分类操作,确认并输出。

重点:对于题意中的第三种的巡逻情况,要注意排重处理,重复的字母输出一遍即可,数量也不需要累加。

参考代码如下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
string name1,name2;//输入两个名字
string same="";//定义一个字符串储存重复的字母`same`
cin>>name1>>name2;
for(int i=0;i<=name1.size();i++)//双重不重复循环枚举两个名字中的每一个字母
{
for(int j=0;j<=name2.size();j++)
{
if(name1[i]==name2[j])
{
same=same+name1[i];//如果两字母相同,将该字母存入`same`串中
}
}
}
int result=same.size();//result变量判断各种情况
if(result==1)
{
cout<<"WuXiao"<<endl;
return 0;
}
if(result==2)
{
cout<<"ZhiHui"<<endl;
cout<<same[0];
}
if(result>2)
{
cout<<"XLuo"<<endl;
int a[300]={},t=0;
for(int i=0;i<=same.size();i++)
{
if(a[t]==a[t-1])t--;//统计时的排重
a[++t]=int(same[i]);//a数组储存每一个相同字母的ascll码值
}
sort(a+1,a+t+1);//acsll码值进行排序
cout<<t-2<<endl;
for(int i=3;i<=t-1;i++)
{
if(a[i]!=a[i-1])//输出时的排重
cout<<char(a[i])<<"-";
}
cout<<char(a[t])<<endl;
}
return 0;
}


T2

2.久知的加密工作

(password.pas/c/cpp)

【问题描述】

2027年,从清华毕业的久知找了一份为一些文件的某些部分加密的工作,加密的部分是一串小写英文字母,加密的规则是这样的:要是连续出现相同的字母,则把他们替换成这个字母的大写形式,后面紧跟相同字母的个数,并把它之前跟之后的两端字符串调换,例如出现bcmatchingaef,则字符串变成:efA6bc。然后重新扫描字符串,直到没有出现相同小写字母为止。

【输入】

原始字符串(长度不大于250)。

【输出】

新的字符串。

【输入输出样例1】

password.in password.out

bcaaaaaaef efA6bc

【输入输出样例2】

password.in password.out

cmmmcefffg gM3cF3ce

样例2解释:cM3cefffg——cefffgM3c——ceF3gM3c——gM3cF3ce

【数据范围】

题意:对字符串的模拟操作。

解析:对样例必须完全理解,才能完成一些如题意出的多次操作的数据,读懂样例非常重要。

思路:while循环模拟操作即可。

由于评测数据出现了问题,oj上还没有ac程序,因为不能确定准确性,暂时不提供示例代码和重点辨析。

T3

3.凯南的括号

(matching.pas/c/cpp)

【问题描述】

在学习括号匹配的时候,凯南在思考一个无聊的问题:能否找出双括号匹配的对数。

具体问题是:给定长度为N(1 <= N <= 50,000)的只包含左右(小)括号的字符串。能否找出相邻的两个左括号,和两个相邻的右括号,并且左括号的位置比右括号的位置靠左。

当然这些两个左右括号很多,最终的问题是:能否找出有多少对不同的连续左右括号对。

例如:给定括号序列 )((()())()),有四对不同的括号对匹配,具体如下,你不必考虑括号匹配的就近原则,只要考虑左括号在右括号左边即可。

1. )((()())())

^^ ^^

2. )((()())())

^^ ^^

3. )((()())())

^^ ^^

4. )((()())())

^^ ^^

【输入】

一个字符串,保证只包含左右小括号。字符创长度为N(1 <= N <= 50,000)

【输出】

一个整数,表示匹配的左右括号对。

【输入输出样例】

matching.in matching.out

)((()())()) 4

【数据范围】

30%数据保证 N<=222.

50%数据保证 N<=2222

100%数据如题目描述。

题意:查找符合括号要求的左右两对括号对并统计可能性。

解析:这道题看似简单,实则不然。没有复杂的题面也没有高级的算法,其实是采用了大数据的策略,数据看似不大,但已经超过两重循环极限。只能采用一重循环扫描的数学统计策略才能ac,而不是拿部分分。

思路:一重循环扫描枚举,统计出现的左右括号次数。如果出现两个连续的左括号就增加统计次数,如果出现两个连续的右括号就将答案累加当前左括号次数。

重点:对于测试点少的题目,统计千万不能有任何差错,一旦有差错就会功亏一篑,失去大量分数。

参考代码如下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
string x;
int f1=0,f2=0;
cin>>x;//输入括号串
int n=x.size();
for(int i=0;i<=n;i++)//循环扫描
{
if(x[i]==x[i+1]&&x[i]=='(')f1+=1;//累加连续两个左括号次数
if(x[i]==x[i+1]&&x[i]==')')f2+=f1;//加法原理累加可能性次数
}
cout<<f2<<endl;//输出
return 0;
}


T4

4.小顾的字符游戏

(moo.pas/c/cpp)

【问题描述】

小顾和同学们喜欢玩一种游戏叫 “Moo”. -

他们总是站在一排,然后依次说出相应的一个字符,如果出错的同学,就要受到惩罚。

下面就是这个游戏的一个序列:

m o o m o o o m o o m o o o o m o o m o o o m o o m o o o o o

这个游戏的序列最初状态是 S(0) “m o o”,也就是初始状态只有3个字符;如果要查询的字符超过3个,就要产生下一个字符序列,产生序列的规则如下:

s(k)是 s(k-1) + “m o … o”(k+2)个’o’ +s(k-1)

下面是相应的序列

S(0) = “m o o”

S(1) = “m o o m o o o m o o”

S(2) = “m o o m o o o m o o m o o o o m o o m o o o m o o”

注意:如果游戏的序列长度不够,就按照以上规则继续往下产生就可以了,所以游戏用的序列是无穷大的。

那么现在问题就出来了:

游戏中第x个人需要说的字符是什么呢?当然只有可能是 ‘m’或’o’.

本题有m(m<=10)个提问,每个提问给一个整数x,你要回答第x个人需要说出的字符数。

【输入】

第一行一个整数m(m<=10)

接下来m行,每行一个整数x (1 <=x<= 10^9)

【输出】

m行,每行一个字符,第i个人需要说的字符。

【输入输出样例1】

moo.in moo.out

2

1

11 m

m

【数据范围】

如题目描述。保证会有部分小数据查询位置在200以内。

题意:求第x个人说的字母。

解析:本题数据量为10的9次方,超出了计算机一秒枚举计算量,肯定需要特殊算法。实际则是一道递归搜索题。

思路:先求出数据范围内每一次操作的字符串长度,然后作为递归长度判断形参使用。利用字符串每一段具有和上一段结构相同的特点进行递归搜索,很快就能搜到答案。

重点:一定要注意递归中复杂的形参传递,对递归深刻理解,就能很快打出代码。

参考代码如下:

#include<bits/stdc++.h>
using namespace std;
long long len[50];//第i次操作后moo串的长度
char search(int n,int k)
{
if(n>len[k])return search(n,k+1);//如果n比k次操作后的moo串大,那么说明操作次数不够,k+1,继续操作
if(n<=len[k-1])return search(n,k-1);//如果n比k-1次操作后的moo串都小,那么说明操作次数太多,k-1,返回上一层
//这波操作后所得所需查找的n在moo串中的第几层
n-=len[k-1];//n不可能在前半段中,直接去除前半段的长度
if(n<=k+3)return (n==1)?'m':'o';//如果在中间段,三目判断
n-=(k+3);//如果不在中间段,去除中间段的长度
return search(n,k-1);//说明在后半段,递归进后半段搜索
}
int main()
{
int m;
len[0]=3;
for(int i=1;i<=40;i++)len[i]=len[i-1]*2+i+3;//模拟每一次操作moo串的长度变化 ,先模拟40次,获得足够的长度数据后储存使用
cin>>m;//如题意
for(int i=1;i<=m;i++)
{
int s;
cin>>s;//输入每一次查询的位置
char result=search(s,1);//形参分别为 (查找的位置,查找的层数)所以从第一层开始查找 ,定义看似无用其实是因为方便递归形参传递
cout<<result<<endl;
}
return 0;
}


总结

加强对题意考察算法内容的理解与猜测,提升字符串基础操作的熟练度。

—————————————————————我是华丽丽的正文分割线——————————————————————

——————————————————————我是讲废话的分割线———————————————————————
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: