NUEQ-ACM2022预备队 2023春 第一次双周赛

文章提供了一系列编程题目,包括重复输出、日期格式化、大笨钟问题、求和阶乘、数字个位数统计、正整数加法、打印沙漏、地图未选格子数量、座位安排和代金券发放等。每题给出了C++代码实现,涉及字符串处理、逻辑运算、数学算法等内容。
摘要由CSDN通过智能技术生成

第一次双周赛

第一题 重要的话说三遍

代码1

#include<iostream>
using namespace std;

int main()
{
    cout << "I'm gonna WIN!" << endl;
    cout << "I'm gonna WIN!" << endl;
    cout << "I'm gonna WIN!" << endl;
    return 0;
}

第二题 日期格式化

代码2

#include<iostream>
using namespace std;

int main()
{
    string s;
    cin >> s;
    cout << s.substr(6, 4) << "-" << s.substr(0, 2) << "-" << s.substr(3,2) << endl;
    return 0;
}

第三题 大笨钟

题目3

0 − 12 0 - 12 012 点不敲钟, 13 − 24 13 - 24 1324 1 − 12 1 - 12 112 下。过了整点就敲下一个整点数。

代码3

#include<iostream>
#include<iomanip>
using namespace std;

int main()
{
    int h, m;
    char t;
    cin >> h >> t >> m;
    //0-12点(包含端点)
    if ((h >= 0 && h < 12) || (h == 12 && m == 0))
    {
        cout << "Only " << setfill('0') << setiosflags(ios::right) << setw(2)<< h << ":" << setfill('0') << setiosflags(ios::right) << setw(2)  << m << ".  Too early to Dang." << endl;
    }
    //其余时间
    else
    {
        for (int i = 0; i < (m == 0 ? h : h + 1) - 12; i++)
        {
            cout << "Dang";
        }
        cout << endl;
    }

    return 0;
}

第四题 拯救外星人

题目4

给出 A A A B B B ( A + B ) ! (A + B)! (A+B)!

代码4

#include<iostream>
using namespace std;

int main()
{
    long long a, b;
    cin >> a >> b;
    long long r = 1;
    for (int i = 1; i <= a + b; i++)
    {
        r *= i;
    }
    cout << r << endl;
    return 0;
}

第五题 个位数统计

题目5

统计一个数字中 0 − 9 0 - 9 09 各个数字出现的次数。

思路5

创建一个数组存储每一个数字出现的次数。

代码5

#include<iostream>
using namespace std;

int main()
{
    //读取字符串更方便处理
    string s;
    cin >> s;
    //存储每一个数字出现的次数
    int f[10] = {};
    for (int i = 0; i < (int)s.size(); i++)
    {
        f[s[i] - '0']++;
    }
    for (int i = 0; i <10; i++)
    {
        //出现0次不需要输出
        if (f[i] != 0)
        {
            cout << i << ":" << f[i] << endl;
        }
    }
    return 0;
}

第六题 正整数A+B

题目6

A + B A + B A+B 的值。但是 A A A B B B 可能为任何字符。如果不是满足要求的正整数则用 ? ? ? 表示。

思路6

因为不保证 B B B 中没有空格,所以需要读取一整行,从读取的字符串中寻找第一个空格,将其分割成 A A A B B B 即可。

代码6

    #include<iostream>
    using namespace std;

    //处理 A 和 B,不符合要求的返回-1
    int process(string& s)
    {
        int n = 0;
        //空字符串不符合二要求
        if (s.size() == 0)
        {
            return -1;
        }
        //遍历每一个字符
        for (int i = 0; i < (int)s.size(); i++)
        {
            //每一位都是数字
            if (s[i] >= '0' && s[i] <= '9')
            {
                n *= 10;
                n += s[i] - '0';
            }
            else
            {
                return -1;
            }
        }
        //正整数不在范围内
        return (n < 1 || n > 1000) ? -1 : n;
    }

    int main()
    {
        //缓冲区
        char s[1024 * 1024];
        //字符串A和B
        string s1, s2;
        //获取一行
        cin.getline(s, sizeof(s));
        //寻找第一个空格
        for (int i = 0; ; i++)
        {
            if (s[i] == ' ')
            {
                //分割A和B
                s1 = string(s, 0, i);
                s2 = string(s + i + 1);
                break;
            }
        }
        //A的处理结果和B的处理结果
        int n1, n2;
        n1 = process(s1);
        n2 = process(s2);
        //小于0代表不符合要求,输出?
        if (n1 < 0)
        {
            cout << "? + ";
        }
        else
        {
            cout << n1 << " + ";
        }
        if (n2 < 0)
        {
            cout << "? = ";
        }
        else
        {
            cout << n2 << " = ";
        }
        //如果A或B不符合要求,结果就是?
        if (n1 < 0 || n2 < 0)
        {
            cout << "?" << endl;
        }
        else
        {
            cout << n1 + n2 << endl;
        }
        return 0;
    }

第七题 打印沙漏

题目7

要求写个程序把给定的符号打印成沙漏的形状。需要用最多的给定字符。

思路7

先找到能使用的最多的字符和这些字符能打印的行数,然后按照行数打印。

代码7

#include<iostream>
using namespace std;

int main()
{
    //n,使用的字符数
    int n ,cnt = 0;
    char c;
    cin >> n >> c;
    //i代表行数,t代表当前使用的字符数
    int i, t = 1;
    //从第一行开始累计使用的字符数(不包括单个字符的那一行,其余行都出现两次)
    for (i = 1; t < n; i++)
    {
        t += 2 * (2 * i + 1);
    }
    //减去循环最后一次的累加
    i--;
    //如果使用的字符数超了,那么行数还需要减一
    if (t != n)
    {
        i--;
    }
    //打印上半部分
    for (int j = i; j > 0; j--)
    {
        //打印空格
        for (int k = 0; k < (i - j); k++)
        {
            cout << ' ';
        }
        //打印字符
        for (int k = 0; k < 2 * j + 1; k++)
        {
            cout << c;
            cnt++;
        }
        cout << endl;
    }
    //打印单个字符的行
    for (int k = 0; k < i; k++)
    {
        cout << ' ';
    }
    cout << c << endl;
    cnt++;
    //打印下半部分
    for (int j = 1; j <= i; j++)
    {
        for (int k = 0; k < (i - j); k++)
        {
            cout << ' ';
        }
        for (int k = 0; k < 2 * j + 1; k++)
        {
            cout << c;
            cnt++;
        }
        cout << endl;
    }
    //打印未使用的字符个数
    cout << n - cnt << endl;
    return 0;
}

第八题 机工士姆斯塔迪奥

题目8

有一个 N × M N \times M N×M 的地图,选择若干行和列,问剩下未被选择的格子数量。

思路8

无论选择哪一行或列,都可以将其任意平移至未被选择的行或列。经过平移,最后可以得到一块矩形的未被选择的多个格子。

代码8

#include<iostream>
using namespace std;

constexpr int maxmn = 1e5 + 5;
//记录被占用的列和行
bool cvis[maxmn], rvis[maxmn];

int main()
{
    long long n, m, q;
    cin >> n >> m >> q;
    long long rcnt = 0, ccnt = 0;
    while (q--)
    {
        int ti, ci;
        cin >> ti >> ci;
        if (ti == 0)
        {
            if (!rvis[ci])
            {
                rvis[ci] = true;
                rcnt++;
            }
        }
        else
        {
            if (!cvis[ci])
            {
                cvis[ci] = true;
                ccnt++;
            }
        }
    }
    //计算结果
    long long cnt = (n - rcnt) * (m - ccnt);
    cout << cnt << endl;
    return 0;
}

第九题 排座位

题目9

N N N 个人,给出这些人间的一些关系:朋友和敌人。朋友也是朋友,但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。
如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but…;如果他们之间只有敌对关系,则输出No way。

思路9

由于朋友的朋友也是朋友,所以要先算出所有人之间是否为简介的朋友。借鉴Floyd算法的思想,可以通过“中转”的方法得到两个人是否为间接的朋友。

代码9

#include<iostream>
using namespace std;

constexpr int maxn = 101;
int n, m, k;
//题目给出的原来的关系
int re[maxn][maxn];
//是否为间接或直接的朋友
int fr[maxn][maxn];

int main()
{
    cin >> n >> m >> k;
    //输入题目的关系
    while (m--)
    {
        int g1, g2, r;
        cin >> g1 >> g2 >> r;
        re[g1][g2] = r;
        re[g2][g1] = r;
        fr[g1][g2] = r;
        fr[g2][g1] = r;
    }
    //计算任意两个人之间是否为朋友
    //i和j是否为朋友,通过kk中转
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            for (int kk = 1; kk <= n; kk++)
            {
                if (fr[i][kk] == 1 && fr[kk][j] == 1)
                {
                    fr[i][j] = 1;
                }
            }
        }
    }

    while (k--)
    {
        int g1, g2;
        cin >> g1 >> g2;
        //是直接的朋友或者是间接的朋友
        if (re[g1][g2] == 1 || (fr[g1][g2] == 1 && re[g1][g2] != -1))
        {
            cout << "No problem" << endl;
        }
        //没有直接关系也不是间接的朋友
        else if (re[g1][g2] == 0 && fr[g1][g2] != 1)
        {
            cout << "OK" << endl;
        }
        //是敌人但有间接的朋友
        else if (re[g1][g2] == -1 && fr[g1][g2] == 1 )
        {
            cout << "OK but..." << endl;
        }
        //是敌人
        else
        {
            cout << "No way" << endl;
        }
    }
    return 0;
}

第十题 名人堂与代金券

题目10

总评成绩必须达到 60 60 60 分及以上,并且有另加福利:总评分在 [ G , 100 ] [G, 100] [G,100] 区间内者,可以得到 50 50 50 元 PAT 代金券;在 [ 60 , G ) [60, G) [60,G) 区间内者,可以得到 20 20 20 元PAT代金券。同时任课老师还会把总评成绩前 K 名的学生列入课程“名人堂”。
列出名人堂的学生,并统计一共发出了面值多少元的 PAT 代金券。

思路10

简单的模拟。按题目要求累计和排序。

代码10

#include<iostream>
#include<algorithm>
using namespace std;

constexpr int maxn = 10000 + 5;
//total是所有 PAT 代金券面值
int n, g, k, total;

//记录学生
struct student
{
    //账号名
    string account;
    //分数和排序
    int score, rank;
} s[maxn];

int main()
{
    cin >> n >> g >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> s[i].account >> s[i].score;
        //累加面值
        if (s[i].score <= 100 && s[i].score >= g)
        {
            total += 50;
        }
        else if (s[i].score < g && s[i].score >= 60)
        {
            total += 20;
        }
    }
    cout << total << endl;
    //先按照分数排序
    sort(s + 1, s + n + 1, [](student& left, student& right){ return left.score > right.score; });
    //同分数的再按照账号名排序,并同时记录排名
    //rank是当前的排名
    int rank = 0, nowscore = 0x3f3f3f3f, samestart = 0;
    for (int i = 1; i <= n; i++)
    {
        //分数变了之后,对前一组同分进行排序,并更新当前的排名位置
        if (nowscore != s[i].score)
        {
            sort(s + samestart, s + i, [](student& left, student& right){ return left.account < right.account; });
            samestart = i;
            rank = i;
            nowscore = s[i].score;
        }
        s[i].rank = rank;
    }
    sort(s + samestart, s + n + 1, [](student& left, student& right){ return left.account < right.account; });
    //输出排名
    int i = 1;
    while (s[i].rank <= k && i <= n)
    {
        cout << s[i].rank << ' ' << s[i].account << ' ' << s[i].score << endl;
        i++;
    }
    return 0;
}

第十一题 包装机

题目11

机器中有 N N N 条轨道,放置了一些物品。轨道下面有一个筐。当某条轨道的按钮被按下时,活塞向左推动,将轨道尽头的一件物品推落筐中。当 0 0 0 号按钮被按下时,机械手将抓取筐顶部的一件物品,放到流水线上。
筐的容量是有限的,当筐已经满了,但仍然有某条轨道的按钮被按下时,系统应强制启动 0 号键,先从筐里抓出一件物品,再将对应轨道的物品推落。此外,如果轨道已经空了,再按对应的按钮不会发生任何事;同样的,如果筐是空的,按 0 0 0 号按钮也不会发生任何事。
给定一系列按钮操作,依次列出流水线上的物品。

思路11

这是一道栈的模拟题。定义一个栈然后模拟操作。

代码11

#include<iostream>
#include<stack>
using namespace std;

constexpr int maxm = 1001, maxn = 101;
int n, m,smax, scnt;
//所有轨道
stack<char> track[maxn];
//框
stack<char> s;

int main()
{
    cin >> n >> m >> smax;
    for (int i = 1; i <= n; i++)
    {
        string t;
        cin >> t;
        //倒序将轨道上的物品放到轨道上
        for (int j = (int)t.size() - 1; j >= 0; j--)
        {
            track[i].push(t[j]);
        }
    }
    while (true)
    {
        int o;
        cin >> o;
        //-1代表中止
        if (o == -1)
        {
            break;
        }
        //0代表抓取筐顶部的一件物品
        if (o == 0)
        {
            //先判断是否为空
            if (!s.empty())
            {
                cout << s.top();
                s.pop();
                scnt--;
            }
        }
        //其余情况是轨道的按钮
        else
        {
            //先判断是否为空
            if (!track[o].empty())
            {
                //框满了,就执行0的操作
                if (scnt == smax)
                {
                    cout << s.top();
                    s.pop();
                    scnt--;
                }
                //入框
                s.push(track[o].top());
                scnt++;
                track[o].pop();
            }
        }
    }
    return 0;
}

第十二题 愿天下有情人都是失散多年的兄妹

题目12

给出家族关系,判断两人是否五服以内。

思路12

可以分别列出两人五服以内所有人,然后判断是否有人同时出现在两组中。

代码12

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;

constexpr int maxn = 1e5 + 5;
int n, k;
//两个人五代以内所有亲属的id
vector<int> id1All, id2All;

//记录每个人的信息
struct person
{
    //性别
    char gender;
    //父亲和母亲的id
    int father = 0, mother = 0;
} people[maxn];

//dfs搜索某人五代以内亲属
void dfs(int step, int id, vector<int>& result)
{
    //向上搜索到第四代中止
    if (step == 4)
    {
        return;
    }
    //父亲有记录,就存进vector
    if (people[id].father > 0)
    {
        result.push_back(people[id].father);
        dfs(step + 1, people[id].father, result);
    }
    //母亲有记录,就存进vector
    if (people[id].mother > 0)
    {
        result.push_back(people[id].mother);
        dfs(step + 1, people[id].mother, result);
    }    
}
//寻找某人五代以内所有亲属
void findAll(int id, vector<int>& result)
{
    result.push_back(id);
    dfs(0, id, result);
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int id;
        cin >> id;
        cin >> people[id].gender >> people[id].father >> people[id]. mother;
        //父亲一定是男性
        if (people[id].father > 0)
        {
            people[people[id].father].gender = 'M';
        }
        //母亲一定是女性
        if (people[id].mother > 0)
        {
            people[people[id].mother].gender = 'F';
        }
    }

    cin >> k;
    while (k--)
    {
        int id1, id2;
        cin >> id1 >> id2;
        //同性
        if (people[id1].gender == people[id2].gender)
        {
            cout << "Never Mind" << endl;
        }
        else
        {
            //清除上次的记录
            id1All.clear();
            id2All.clear();
            //查找
            findAll(id1, id1All);
            findAll(id2, id2All);
            //标记是否有同时出现在两组之中的人
            bool exist = false;
            for (int i = 0; i < (int)id1All.size(); i++)
            {
                for (int j = 0; j < (int)id2All.size(); j++)
                {
                    if (id1All[i] == id2All[j])
                    {
                        exist = true;
                        break;
                    }
                }
            }
            cout << (exist ? "No" : "Yes") << endl;
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值