2021年浙江工商大学新生赛题解

  • 本篇中的题目顺序为预期难度顺序,并非比赛题目顺序
  • 本篇中所有的“更好的优化”均为标准答案之外的思考,不使用此内容也可以通过题目

本文为拷贝版本,可能存在图片丢失等问题,不修复,请前往原地址查看

原文地址
Cloud Flare 网页镜像地址

比赛预期情况

总共比赛人数:175 (至少通过一道题的人数,没有通过题的不计入总人数)

题目名 实际通过次数 实际通过比例 预期通过比例
chiking 的偶像 “EDIT” “EDIT” 100%
chiking 和珂朵莉 “EDIT” “EDIT” 80%
chiking 的序列 II “EDIT” “EDIT” 60%
chiking 的序列 I “EDIT” “EDIT” 50%
chiking 的棋盘 “EDIT” “EDIT” 30%
乐于助人的 chiking “EDIT” “EDIT” 20%
chiking 的俄罗斯方块 “EDIT” “EDIT” 1%
chiking 和大家一起来做签到题 “EDIT” “EDIT” 1%
chiking 是一个机器人 “EDIT” “EDIT” 1%

P.S. “EDIT” 部分懒得数了,先凑合看一下

题解

chiking 的偶像

大致题意

循环输出 \soup_god/,且总共输出的字符串长度为 n n n

思路

简单的签到题,只需要还记得有 mod 这个运算就能写出来

AC Code

#include "bits/stdc++.h"

using namespace std;

void solve() {
   
   
    const char *data = "\\soup_god/";
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) {
   
   
        cout << data[i % 10];
    }
    cout << endl;
}

chiking 和珂朵莉

大致题意

n n n 个物品,每个物品都有价值和所属类别,让你选择 n − k n - k nk 种类别的物品,使得所选出来的这些类别的物品的总价值最大

思路

也是签到题之一

在读入数据的时候统计每个类别的物品价值只和,之后排序一下,取出后 n − k n - k nk 个类别的价值即可

AC Code

#include "bits/stdc++.h"

using namespace std;

void solve() {
   
   
    int w[11] = {
   
   0};
    int m, n, k;
    cin >> m >> n >> k;
    for (int i = 0; i < m; ++i) {
   
   
        int d, s;
        cin >> d >> s;
        w[s] += d;
    }
    sort(w + 1, w + n + 1);
    int ans = 0;
    for (int i = k + 1; i <= n; ++i) ans += w[i];
    cout << ans << endl;
}

吐槽

这道题原来有一个小坑点,即物品的价值可以为负数,所以需要额外增加一个判断,但是想了想还是当签到题,不要故意恶心了,于是就删掉了。所以顺便好奇的问一下,有多少人看到题面之后去想过价值是不是可能为负数呢

chiking 的序列 II

大致题意

有一个非递减的数组,允许你进行任意次数操作,每次操作可以使得其中一个值增加 1 1 1,问至少需要多少次操作才能使得数组内没有相同的值

思路

因为只能进行加法运算,所以数字只会增加,由于已经排序好了数组,所以最简单的方案就是让每一个值都比前一个值要大即可

AC Code

#include "bits/stdc++.h"

using namespace std;

void solve() {
   
   
    int n;
    cin >> n;
    vector<int> data(n);
    for (int i = 0; i < n; ++i) cin >> data[i];
    long long sum = 0;
    for (int i = 1; i < n; ++i) {
   
   
        int tmp = max(data[i - 1] + 1, data[i]);
        sum += tmp - data[i];
        data[i] = tmp;
    }
    cout << sum << endl;
}

chiking 的序列 I

大致题意

有一个数组,允许你进行任意次操作,每次执行操作可以将任意一个数字插入到数组到任意位置,问至少需要多少次操作才能使得数组内到每一个值满足 a i ≤ i a_i \leq i aii,其中 i i i 表示下标

思路

首先要让每一位的的数字小于等于其下标,那么插入的数字也不能例外。由于插入的数字可以是任意值,所以理所应当的,选择 1 1 1 进行插入是最好的选择,因为无论插入何处均可以使得新插入的数字不再需要考虑

接下来是考虑插入位置的问题,在等式中 a i a_i ai 是不可更新的值,所以只能想办法使得 i i i 增大,那么最容易得到的解决方案就是将数字插入数组开头,这会使得所有原来在数组内的值的下标都增大,最大程度的满足条件

接下来考虑插入数量的问题,由于都是插入数组最前面,所以可以将等式改写为 a i < = i + x a_i <= i + x ai<=i+x,其中的 x x x 即为需要求解的值。那么对于每一个 i i i 都要满足这个等式,所以遍历一次数组,找出最大的需要的 x x x 即可

AC Code

#include "bits/stdc++.h"

using namespace std;

void solve() {
   
   
    int _;
    cin >> _;
    for (int ts = 0; ts < _; ++ts) {
   
   
        int n;
        cin >> n;
        int ans = 0;
        for (int i = 0; i < n; ++i) {
   
   
            int tmp;
            cin >> tmp;
            ans = max(ans, tmp - i - 1);
        }
        cout << ans << endl;
    }
}

chiking 的棋盘

大致题意

k k kL 形状的方块能否平铺一个矩形方格

思路

我们可以用 L 形状的方块拼出如下两种最简平铺方案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JhYBmf9b-1639041859538)(/image/acm/2021-ZJGSU-ACM-freshman-competition/2*4.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q0HQwnc4-1639041859539)(/image/acm/2021-ZJGSU-ACM-freshman-competition/3*8.png)]

这两个方案都是 8 8 8 个方格的倍数,所以起码,方格总数应该是 8 8 8 的倍数,即 n × m = 8 k n \times m = 8k n×m=8k

  1. 假设两边都是偶数,那么必然其中一边为 2 2 2 的倍数,另外一边为 4 4 4 的倍数,所以必然可以被仅靠第一种平铺方案平铺
  2. 假设一边为奇数一边是偶数,那么必然其中一边为 8 8 8 的倍数,而第一种方案也可以改写为 2 ∗ 8 2 * 8 28 的方格,即只需要另外一边可以分解为 2 x + 3 y 2x + 3y 2x+3y 的形式即可,易得只要 $ \geq 2$ 的值均可

所以结论:只要满足方格数为 8 8 8 的倍数,且两边都 $ \geq 2$,则必定可以平铺

接下来只需要计算数量对不对就行

AC Code

#include "bits/stdc++.h"

using namespace std;

void solve() {
   
   
#define int long long
    int _;
    cin >> _;
    for (int ts = 0; ts < _; ++ts) {
   
   
        int n, m, k;
        cin >> n >> m >> k;
        if (n > 1 && m > 1 && (n * m) % 8 == 0) {
   
   
            int cnt = (n * m / 4);
            if (cnt == k) cout << "Perfect!\n";
            else cout << "Single forever!\n";
        } else cout << "Single forever!\n";
    }
}

乐于助人的 chiking

大致题意

允许将字符串中 oou 互转,也允许将字符串的 khh 互转的前提下,计算给出的字符串数组中有几个不同的字符串

思路

由于存在转换,所以最好的办法就是统一转为一种类型,再进行比较

oou 这对规则,若我们将所有的 oo 转为 u,那么当遇到 ouuo 时,会发现在此条规则下应该是相等的字符串没有相等。所以应该将所有的 u 字符转为 oo

khh 这对规则,若我们将所有的 h 转为 kh,那么就会出现 kh 还可以继续转为 kkhkkkhkkkkh 等,所以只能选择将 kh 转为 h。但是请注意 kkkh 这类连续的 k 的情况,可以连续多次转换

处理完成后,统计不同的字符串的数量即可

处理字符串复杂度 O ( n m ) = 1 e 5 O(nm) = 1e5 O(nm)=1e5
统计不同字符串数量 O ( n 2 m ) = 1 e 7 O(n^2m) = 1e7 O(n2m)=1e7

满足要求

AC Code

#include "bits/stdc++.h"

using namespace std;

char a[1010], b[2010];

void solve() {
   
   
    int n;
    cin >> n;
    vector<string> data;
    for (int i = 0; i < n; ++i) {
   
   
        cin >> a;
        int len = (int) strlen(a);
        int pos = 0;
        for (int j = 0; j < len; ++j) {
   
   
            if (a[j] == 'u') {
   
   
                b[pos++] = 'o';
                b[pos++] = 'o';
            } else if (a[j] == 'h') {
   
   
                while (pos > 0 && b[pos - 1] == 'k') pos--;
                b[pos++] = 'h';
            } else {
   
   
                b[pos++] = a[j];
            }
            b[pos] = 0;
        }
        data.emplace_back(b);
    }
    int cnt = 0;
    for (int i = 0; i < n - 1; ++i) {
   
   
        bool flag = true;
        for (int j = i + 1; j < n; ++j) {
   
   
            if (data[i] == data[j]) {
   
   
                flag = false;
                break;
            }
        }
        if (flag) cnt++;
    }
    cout << cnt + 1 << endl;
}

更好的优化

实际上,这里需要比较的是字符串是否相同,所以可以使用字符串 hash 来解决,这样,复杂度将会降低至 O ( n m ) O(nm)

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值