2023年8月7日普及组南外集训题解

A 坐车

题目描述

有辆公交车,它可以承载35人,包括一个司机。车子最后一排有4个座位,其他10排都有3个座位。每个上车的人,都会先往左边坐(司机所在的那侧)。现在告诉你,有多少人在车上,绘制车内情况。

输入格式

一个整数 \(n\) ,表示有多少个人在车上。\((1≤n≤34)\)

输出格式

输出车内情况,用D表示司机,O表示有人坐,#表示位置上没有人。 具体可以看样例。

样例1

输入

9

输出

+------------------------+
|O.O.O.#.#.#.#.#.#.#.#.|D|)
|O.O.O.#.#.#.#.#.#.#.#.|.|
|O.......................|
|O.O.#.#.#.#.#.#.#.#.#.|.|)
+------------------------+

题解

我们可以用一个二维字符数组来存储初始状态,这样方便我们最后的输出,从样例中可以发现只有最后一列是特殊的,其他的除以三就行了

ac代码

#include <iostream>
using namespace std;
const int N = 35;
char s[50][50] = {
    "+------------------------+", "|#.#.#.#.#.#.#.#.#.#.#.|D|)", "|#.#.#.#.#.#.#.#.#.#.#.|.|",
    "|#.......................|", "|#.#.#.#.#.#.#.#.#.#.#.|.|)", "+------------------------+"
};
int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= 11; i++) {
        for (int j = 1; j <= 4; j++) {
            if (i != 1 && j == 3)
                continue;
            if (n)
                s[j][2 * i - 1] = 'O', n--;
        }
    }
    for (int i = 0; i < 6; i++) puts(s[i]);
}

B 猜数字

题目描述

猜数字游戏啦!给你如下四种提示:

(1)这个数严格大于x吗?

(2)这个数严格小于x吗?

(3)这个数大于等于x吗?

(4)这个数小于等于x吗?

每个提示,都会给出相应的答案,yes或者no。

如果有多个数满足条件,输出最小的。如果不存在这样的数,输出“Impossible”。

输入格式

第一行输入一个整数 \(n\)

接下来 \(n\) 行,每行一个字符串“sign x answer”,是四个提示的中的一个。

sign是“>”,"<","<=",">="; answer 是“Y”或者"N" ;

如(1)就会有类似这样的字符串“ > x Y” 或者“ > x N”;

输出格式

如果最终的答案有下界的,则输出这个下界

如果存在答案,但是答案没有下界,输出-2000000000

否则输出“Impossible”

样例1

输入

4
>= 1 Y
< 3 N
<= -3 N
> 55 N

输出

3

样例2

输入

2
> 100 Y
< -100 Y

输出

Impossible

题解

非常简单的分支结构,开始时记得定义好上下界就行了

ac代码

#include <iostream>
using namespace std;
int n, o;
int maxx, minn, up, down;
int main() {
    cin >> n;
    minn = down = -2000000000;
    maxx = up = 2000000000;
    for (int i = 0; i < n; i++) {
        char sign[2], flag;
        int a;
        cin >> sign >> a >> flag;
        if (flag == 'Y' && sign[0] == '>') {
            if (sign[1] == '=')
                minn = max(minn, a);
            else
                minn = max(minn, a + 1);
        } else if (flag == 'N' && sign[0] == '>') {
            if (sign[1] == '=')
                maxx = min(maxx, a - 1);
            else
                maxx = min(maxx, a);
        } else if (flag == 'Y' && sign[0] == '<') {
            if (sign[1] == '=')
                maxx = min(maxx, a);
            else
                maxx = min(maxx, a - 1);
        } else if (flag == 'N' && sign[0] == '<') {
            if (sign[1] == '=')
                minn = max(minn, a + 1);
            else
                minn = max(minn, a);
        }
    }
    if (maxx >= minn)
        cout << minn << '\n';
    else
        cout << "Impossible\n";
    return 0;
}

C IwantMoreAC

题目描述

学完Fibonacci序列,YY觉得数字太单调了,她打算用 \(S_n=S_{n-2}+S_{n-1}\) 的递推式去操作字符串。如果 \(S_0=AC\)\(S_1=ACB\),则 \(S_2=ACACB\)。现在YY有两个字符串 \(S_0\)\(S_1\),她想知道,\(S_n\) 中包含多少个"AC"串。

输入格式

第一行两个字符串 \(S_0\)\(S_1\) 和一个数字 \(n\)

输出格式

输出中包含多少个"AC"

样例1

输入

AC AC 3  

输出

3

样例2

输入

ACA CB 2

输出

2

数据范围与提示

样例一中 \(S_3\) =”ACACAC”,所以有3个AC

对于30%的数据,\(S_0\)\(S_1\) 的长度不超过 \(5\)\(n\) 不超过 \(5\)

对于60%的数据,\(S_0\)\(S_1\)和首尾都不包含字母‘A’和‘C'。

对于100%的数据,\(S_0\)\(S_1\)由大写字母构成,长度不超过 \(10\)\(n\) 不超过 \(40\)

题解

用递推算出最终串是不行的,会超时,其实只需要看两个串拼接后会不会产生新的 “AC” 就行了

ac 代码

#include <iostream>
#include <cstring>
using namespace std;
string s0, s1;
int n, cnt2, cnt1, cnt;
int main() {
    cin >> s0 >> s1 >> n;
    for (int i = 1; i < s0.size(); i++)
        if (s0[i] == 'C' && s0[i - 1] == 'A')
            cnt++;
    for (int i = 1; i < s1.size(); i++)
        if (s1[i] == 'C' && s1[i - 1] == 'A')
            cnt1++;
    char a = s0[0], b = s0[s0.size() - 1], c = s1[0], d = s1[s1.size() - 1];
    for (int i = 1; i < n; i++) {
        cnt2 = cnt + cnt1;
        if (b == 'A' && c == 'C')
            cnt2++;
        swap(a, c);
        b = d;
        cnt = cnt1;
        cnt1 = cnt2;
    }
    cout << cnt2;
    return 0;
}

D 体检

题目描述

小王考入了大学,开学前需要去医院体检。
体检一共有 \(N\) 个项目,每个项目检查处都排起了队伍,并且人越来越多。
他一眼就发现,对于第 \(i\) 个项目,如果立即去排队,需要 \(a_i\) 秒才能完成;
如果先做其他检查,在秒后再来,那么要再多等上 \(b_i×t\) 秒。
请你帮他规划,如何安排个项目的顺序,才能尽早完成所有检查。

输入格式

第一行,整数 \(N\) \((1\leq N\leq10^5)\)
下面 \(N\) 行,每行两个整数 \(a,b\)

输出格式

一个整数,表示最早完成检查的耗时.(答案对31536000取模)

样例1

输入

5
1 2
2 3
3 4
4 5
5 6

输出

1419

题解

我们可以贪心中的相邻交换思想

第一种:先 \(i\)\(j\) 式子为: \(t+t×b[i]+a[i]+(t+a[i])×b[j]+a[j]\)

第二种:先 \(j\)\(i\) 式子为: \(t+t×b[j]+a[j]+(t+a[j])×b[i]+a[i]\)

假设第一个式子为 \(f(i,j)\) 第二个式子为 \(f(j,i)\)

那么我们就可以得到 \(f(i,j)-f(j,i)=a[i]×b[j]-a[j]×b[i]\)

我们就以此进行排序小的在前,大的在后

注意要开 long long ,并且答案算一次模一次,否则会溢出

ac代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100005, P = 31536000;
int n;
LL ans;
struct node {
    LL a, b;
} a[N];
bool cmp(node x, node y) { return (x.a * y.b) < (y.a * x.b); }
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i].a >> a[i].b;
    sort(a, a + n, cmp);
    for (int i = 0; i < n; i++) {
        ans = (ans + a[i].a + ans * a[i].b) % P;
    }
    cout << ans;
    return 0;
}

E 推箱子

题目描述

推箱子应该算是一个家喻户晓的游戏了,这次你的任务就是用电脑算出如何移动人物,完成推箱子。

为了使问题简化,数据中只有3个箱子和3个洞。

注:人一次只能推动一个箱子,箱子推到洞上后不会消失,还可以被推出去,只有当三个箱子同时在洞中时,游戏结束

输入格式

第一行两个整数n和m,表示地图的大小

接下来n行,每行m个元素。

"."表示空地,"#"表示墙

"*"表示箱子

"@"表示洞

"X"表示人

输出格式

输出最少的步数完成游戏,如果无法完成游戏输出-1.

样例1

输入

4 4
....
..*@
..*@
.X*@

输出

7

样例2

输入

6 4
@@@#
#*.#
#X.#
.**.
...#
..##

输出

22

样例3

输入

6 6
...#@.
@..*..
#*##..
..##*#
..X...
.@#...

输出

11

题解

首先,我们不需要存入整张地图,那样会导致内存过大,我们可以只存人的位置,以及三个箱子的位置

因为需要判重的原因,所以数据大概有8的8次方,使用8维的数组来判重

先枚举人的位置,如果遇到了箱子,那就让箱子跟着人移动,不过要注意,箱子要比人往前一个身位,并且不能重叠或出界,具体可以看代码的注释

ac代码

#include <iostream>
using namespace std;
// 8^8 = 16777216
const int N = 17000000, M = 10;
bool st[M][M][M][M][M][M][M][M] = { 0 };  //人、三个箱子的 (x,y)
char mp[M][M];
int dx[4] = { 1, 0, -1, 0 }, dy[4] = { 0, 1, 0, -1 };
int n, m;
struct node {
    int step, x[4], y[4];  //步数、三个箱子的 (x,y)
} q[N];
//判断是否出界以及是否能走
bool isoutside(int i, int j) {
    if (i > 0 && i <= n && j > 0 && j <= m && mp[i][j] != '#')
        return true;
    return false;
}
//判重
bool isrepeat(node t) { return st[t.x[0]][t.y[0]][t.x[1]][t.y[1]][t.x[2]][t.y[2]][t.x[3]][t.y[3]]; }
//记录重复
void recordrepeat(node t) { st[t.x[0]][t.y[0]][t.x[1]][t.y[1]][t.x[2]][t.y[2]][t.x[3]][t.y[3]] = true; }
int bfs() {
    int hh = 0, tt = 0;
    while (hh <= tt) {
        node a = q[hh++];
        for (int i = 0; i < 4; i++) {
            node t = a;
            t.x[0] += dx[i];
            t.y[0] += dy[i];  //人朝四个方向移动
            if (!isoutside(t.x[0], t.y[0]))
                continue;
            bool flag = false;  //记录结果是否合法
            for (int j = 1; j < 4; j++) {
                // 人与箱子重叠
                if (t.x[0] == t.x[j] && t.y[0] == t.y[j]) {
                    t.x[j] += dx[i];
                    t.y[j] += dy[i];  //箱子比人要前一个身位
                    //此时箱子的位置比人会前一个身位,这要求没有箱子在那里,不然就没地放了
                    for (int k = 1; k < 4; k++) {
                        if (k == j)
                            continue;  //不会跟自己重叠
                        if (t.x[j] == t.x[k] && t.y[j] == t.y[k]) {
                            flag = true;  //不合法的操作
                            break;
                        }
                    }
                    //出界了
                    if (!isoutside(t.x[j], t.y[j])) {
                        flag = true;  //不合法的操作
                        break;
                    }
                }
            }
            if (flag)
                continue;  //此时走的方向是无解的,换一个方向
            //合法的话,步数加1
            t.step++;
            flag = true;  //记录是否所有箱子都进洞了,既箱子的位置是不是洞
            for (int j = 1; j < 4; j++) {
                if (mp[t.x[j]][t.y[j]] != '@') {
                    flag = false;
                    break;
                }
            }
            //如果都进洞了,返回结果
            if (flag)
                return t.step;
            //判重
            if (isrepeat(t))
                continue;
            recordrepeat(t);
            q[++tt] = t;
        }
    }
    return -1;
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
    int cnt = 1;  //到了第几个箱子
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            //人的位置记录
            if (mp[i][j] == 'X') {
                q[0].x[0] = i;
                q[0].y[0] = j;
            }
            //箱子的位置记录
            if (mp[i][j] == '*') {
                q[0].x[cnt] = i;
                q[0].y[cnt] = j;
                ++cnt;
            }
        }
    }
    q[0].step = 0;  //初始化步数
    printf("%d", bfs());
    return 0;
}
posted @ 2023-08-07 21:42  typerxiaozhu  阅读(76)  评论(0编辑  收藏  举报