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

模拟赛题目来自自行设计

严禁转载

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

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

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

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

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;
}

总结

加强对题意考察算法内容的理解与猜测,提升字符串基础操作的熟练度。
—————————————————————我是华丽丽的正文分割线——————————————————————

——————————————————————我是讲废话的分割线———————————————————————

猜你喜欢

转载自blog.csdn.net/prasnip_/article/details/78823072
今日推荐