2018年天梯赛-全国总决赛

L1-1 天梯赛座位分配 (20 分)(待补)

题意:

天梯赛每年有大量参赛队员,要保证同一所学校的所有队员都不能相邻,分配座位就成为一件比较麻烦的事情。为此我们制定如下策略:假设某赛场有 N 所学校参赛,第 i 所学校有 M[i] 支队伍,每队 10 位参赛选手。令每校选手排成一列纵队,第 i+1 队的选手排在第 i 队选手之后。从第 1 所学校开始,各校的第 1 位队员顺次入座,然后是各校的第 2 位队员…… 以此类推。如果最后只剩下 1 所学校的队伍还没有分配座位,则需要安排他们的队员隔位就坐。本题就要求你编写程序,自动为各校生成队员的座位号,从 1 开始编号。

思路:

代码:

L1-2 倒数第N个字符串 (15 分)

题意:

给定一个完全由小写英文字母组成的字符串等差递增序列,该序列中的每个字符串的长度固定为 L,从 L 个 a 开始,以 1 为步长递增。例如当 L 为 3 时,序列为 { aaa, aab, aac, ..., aaz, aba, abb, ..., abz, ..., zzz }。这个序列的倒数第27个字符串就是 zyz。对于任意给定的 L,本题要求你给出对应序列倒数第 N 个字符串。

思路:

正解的思路应该是先求字符串所有的种类数,再减去x,就能得到第x大的字符串然后使用26进制的转换,模拟时,我用暴力模拟不停的开个vector放字符串输出,会扣三分。

代码:

#include<bits/stdc++.h>
#include<unordered_map>

using namespace std;

int main()
{
    int l,r,i,x,j;
    cin>>l>>x;
    int d1=pow(26,l)-x;;
    string s1;
    vector<char >ans;
    while(d1!=0)
    {
        int x;
        x=d1%26;
        d1/=26;
        ans.push_back(x+'a');
    }
    reverse(ans.begin(),ans.end());
    for(auto x:ans) cout<<x;
    cout<<endl;
    return 0;
}

L1-3 打折 (5 分)

题意:

去商场淘打折商品时,计算打折以后的价钱是件颇费脑子的事情。例如原价 ¥988,标明打 7 折,则折扣价应该是 ¥988 x 70% = ¥691.60。本题就请你写个程序替客户计算折扣价。

思路:

简单题直接输出

#include<bits/stdc++.h>

using namespace std;

int main()
{
    double n,x;
    cin>>n>>x;
    cout<<fixed<<setprecision(2)<<(n*x*0.1)<<endl;
}

L1-4 2018我们要赢 (5 分)

题意:

2018年天梯赛的注册邀请码是“2018wmyy”,意思就是“2018我们要赢”。本题就请你用汉语拼音输出这句话。

思路:

直接输出即可

代码:

#include<bits/stdc++.h>

using namespace std;

int main()
{
    cout<<"2018\nwo3 men2 yao4 ying2 !"<<endl;
}

L1-5 电子汪 (10 分)

题意:

据说汪星人的智商能达到人类 4 岁儿童的水平,更有些聪明汪会做加法计算。比如你在地上放两堆小球,分别有 1 只球和 2 只球,聪明汪就会用“汪!汪!汪!”表示 1 加 2 的结果是 3。

本题要求你为电子宠物汪做一个模拟程序,根据电子眼识别出的两堆小球的个数,计算出和,并且用汪星人的叫声给出答案。

思路:

直接输出a+b次狗叫就行

代码:

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int a,b;
    cin>>a>>b;
    for(int i=0;i<a+b;i++)cout<<"Wang!";
}

L1-6 福到了 (15 分)

题意:

“福”字倒着贴,寓意“福到”。不论到底算不算民俗,本题且请你编写程序,把各种汉字倒过来输出。这里要处理的每个汉字是由一个 N × N 的网格组成的,网格中的元素或者为字符 @ 或者为空格。而倒过来的汉字所用的字符由裁判指定。

思路:

输入按许顺入就行,输出的时候留一下,先倒着存好然后进行比较,相同就输出"bu yon dao le",具体就看代码吧。

代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn=105;
char  m1[maxn][maxn],m2[maxn][maxn];
int n,m;
bool check()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            if(m1[i][j]!=m2[i][j]) return false;
    }
    return true;
}
int main()
{
    char x;
    int i,j,d;
    cin>>x>>n;(m=n);
    getchar();
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            m1[i][j]=getchar();
        }
        getchar();
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            m2[i][j]=m1[n-i+1][n-j+1];
        }
    }
    if(check())
    {
        cout<<"bu yong dao le"<<endl;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
             if(m2[i][j]!=' ')
             {
                 cout<<x;
             }
             else
             {
                 cout<<' ';
             }
        }
        cout<<endl;
    }
}

L1-7 谁是赢家 (10 分)

题意:

某电视台的娱乐节目有个表演评审环节,每次安排两位艺人表演,他们的胜负由观众投票和 3 名评委投票两部分共同决定。规则为:如果一位艺人的观众票数高,且得到至少 1 名评委的认可,该艺人就胜出;或艺人的观众票数低,但得到全部评委的认可,也可以胜出。节目保证投票的观众人数为奇数,所以不存在平票的情况。本题就请你用程序判断谁是赢家。

思路:

稍微判断一下,对着题意模拟即可,判断其中一人赢需要的条件,然后else输出一下即可

代码:

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int pa,pb;
    int d1,d2,d3;
    cin>>pa>>pb;
    cin>>d1>>d2>>d3;
    if(d1+d2+d3==0||(d1+d2+d3!=3)&&pa>pb)
    {
        cout<<"The winner is a: "<<pa<<" + "<<3-(d1+d2+d3)<<endl;
    }
    else   
    {
        cout<<"The winner is b: "<<pb<<" + "<<(d1+d2+d3)<<endl;
    }
    return 0;
}

L1-8 猜数字 (20 分)

题意:

一群人坐在一起,每人猜一个 100 以内的数,谁的数字最接近大家平均数的一半就赢。本题就要求你找出其中的赢家。

思路:

题目要求其实可以提出来,假设第i个人猜的数为ai,且所有人的数字之和为sum,那么本质就是找找对于每个i,找abs(\frac{sum}{2*n}-a_{i})的最小值,这里我怕精度,于是直接转abs(sum-2*n*a_{i})

代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn=1e5;
struct node {
    string name;
    int val;
}mo[maxn];
bool cmp1(node a,node b )
{
    return a.val<b.val;
}
int main()
{
    int n,i,j,t,sum=0;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>mo[i].name>>mo[i].val;
        sum+=mo[i].val;
    }
    for(i=0;i<n;i++)
    {
        mo[i].val=abs(sum-mo[i].val*2*n);
    }
    sort(mo,mo+n,cmp1);
    cout<<(int)(sum/(n*2))<<" "<<mo[0].name<<endl;
    return 0;
}

L2-1 分而治之 (25 分)

题意:

分而治之,各个击破是兵家常用的策略之一。在战争中,我们希望首先攻下敌方的部分城市,使其剩余的城市变成孤立无援,然后再分头各个击破。为此参谋部提供了若干打击方案。本题就请你编写程序,判断每个方案的可行性。

输入:

输入在第一行给出两个正整数 N 和 M(均不超过10 000),分别为敌方城市个数(于是默认城市从 1 到 N 编号)和连接两城市的通路条数。随后 M 行,每行给出一条通路所连接的两个城市的编号,其间以一个空格分隔。在城市信息之后给出参谋部的系列方案,即一个正整数 K (≤ 100)和随后的 K 行方案,每行按以下格式给出:

Np v[1] v[2] ... v[Np]

其中 Np 是该方案中计划攻下的城市数量,后面的系列 v[i] 是计划攻下的城市编号。

输出:

对每一套方案,如果可行就输出YES,否则输出NO

思路:

一开始读题读错了,一定要注意他题意其实是说,把方案数里的所有城市关闭,那么剩下的城市是否能全部被孤立,孤立就是说没有和其他城市相连,那么其实你按照题意把树建好之后,将攻下的城市打下标机,然后每个点遍历,只要有一个点能去往其他城市,直接输出NO。

代码:

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

const int maxn=10005;
int N,M;
vector<int >edges[maxn];
int main()
{
    int i,j;
    cin>>N>>M;
    for(i=0;i<M;i++)
    {
        int a,b;
        cin>>a>>b;
        edges[a].push_back(b);
        edges[b].push_back(a);
    }
    int k;
    cin>>k;
    unordered_map<int ,int >mo;
    while(k--)
    {
        int d,flag=0;
        cin>>d;
        vector<int> qry(d);
        for(int &i:qry ){
             cin>>i;
             mo[i]=1;
        }
        for(i=1;i<=N;i++)
        {
            if(mo[i]==0)
            {
                for(j=0;j<edges[i].size();j++)
                {
                    if(mo[edges[i][j]]==0) {
                        flag=1;
                        cout<<"NO"<<endl;
                        break;
                    }
                }
            }
            if(flag==1) break;
        }
        if(flag==0){
            cout<<"YES"<<endl;
        }
        mo.clear();
    }
    return 0;
}

L2-2 小字辈 (25 分)

题意:

输入在第一行给出家族人口总数 N(不超过 100 000 的正整数) —— 简单起见,我们把家族成员从 1 到 N 编号。随后第二行给出 N 个编号,其中第 i 个编号对应第 i 位成员的父/母。家谱中辈分最高的老祖宗对应的父/母编号为 -1。一行中的数字间以空格分隔。

思路:

把成员和父母之间的关系连边建好,对于每个i来说a[i]就是父节点,i就是子节点,-1就是源头,然后从源头开始bfs,对每个边打上深度标机,然后找深度最大的再输出即可。

代码:

#include<bits/stdc++.h>
#include<unordered_map>

using namespace std;

const int maxn=100005;
int a[maxn];
int main()
{
    int n,i,j,t;
    cin>>n;
    vector<int >edges[n];
    for(i=0;i<=n;i++) {
        edges[i].clear();
    }
    for(i=1;i<=n;i++)
    {
        cin>>a[i];
        if(a[i]==-1) a[i]=0;
        edges[a[i]].push_back(i);
    }
    deque<int >qq;
    qq.push_back(0);
    unordered_map<int ,int >mo;
    mo[0]=1;
    int ans=1;
    while(!qq.empty())
    {
        int d1=qq.front();
        qq.pop_front();
        for(i=0;i<edges[d1].size();i++)
        {
             if(mo[edges[d1][i]]==0)
             {
                 mo[edges[d1][i]]=mo[d1]+1;
                 qq.push_back(edges[d1][i]);
                 ans=max(ans,mo[d1]+1);
             }
        }
    }
    cout<<ans-1<<endl;
    vector<int >ans1;
    for(auto &[a,b]:mo)
    {
        if(b==ans)
        {
            ans1.push_back(a);
        }
    }
    sort(ans1.begin(),ans1.end());
    for(i=0;i<ans1.size()-1;i++) cout<<ans1[i]<<" ";
    cout<<ans1[i]<<endl;
}

L2-3 名人堂与代金券 (25 分)

题意:

对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,总评成绩必须达到 60 分及以上,并且有另加福利:总评分在 [G, 100] 区间内者,可以得到 50 元 PAT 代金券;在 [60, G) 区间内者,可以得到 20 元PAT代金券。全国考点通用,一年有效。同时任课老师还会把总评成绩前 K 名的学生列入课程“名人堂”。本题就请你编写程序,帮助老师列出名人堂的学生,并统计一共发出了面值多少元的 PAT 代金券。

输入格式:

输入在第一行给出 3 个整数,分别是 N(不超过 10 000 的正整数,为学生总数)、G(在 (60,100) 区间内的整数,为题面中描述的代金券等级分界线)、K(不超过 100 且不超过 N 的正整数,为进入名人堂的最低名次)。接下来 N 行,每行给出一位学生的账号(长度不超过15位、不带空格的字符串)和总评成绩(区间 [0, 100] 内的整数),其间以空格分隔。题目保证没有重复的账号。

输出格式:

首先在一行中输出发出的 PAT 代金券的总面值。然后按总评成绩非升序输出进入名人堂的学生的名次、账号和成绩,其间以 1 个空格分隔。需要注意的是:成绩相同的学生享有并列的排名,排名并列时,按账号的字母序升序输出。

思路:

非常简单的一道题,直接一个结构体排序重载一下即可。

#include<bits/stdc++.h>
#include<unordered_map>

using namespace std;

const int maxn=10005;
struct node{
    string s1;
    int val;
}mo[maxn];
bool cmp1(node a,node b )
{
    return a.val<b.val;
}
int main()
{
    int n,g,k,sum=0,i,j;
    cin>>n>>g>>k;
    for(i=0;i<n;i++)
    {
        cin>>mo[i].s1>>mo[i].val;
        if(mo[i].val>=60&&mo[i].val<g)
            sum+=20;
        else if(mo[i].val>=g)
            sum+=50;
    }
    cout<<sum<<endl;
    sort(mo,mo+n,cmp1);
    for(i=1;i<=n;i++)
    {
        if(mo[i].val<=mo[k].val)
        cout<<i<<" "<<mo[i].s1<<" "<<mo[i].val<<endl;
        else
            break;
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值