CSDN竞赛—第六期题解与感想

CSDN编程竞赛报名地址:https://edu.csdn.net/contest/detail/16

前言/背景

第二次参加 CSDN 竞赛了,上次赛后提了好多意见,不知道官方有没有看

不过相比上次,这次比赛确实优化了不少

比如页面内复制粘贴不会被警告了,界面也没有那么简陋了(但还是希望能继续优化)

此外还有一些方面想要反馈一下:

  • 能否考虑 C++ 代码模板加上 using namespace std;
  • 希望题目难度方面再多斟酌下,有难有易有区分比较好
  • 能否考虑统一竞赛开始时间,而不是用户自己选择时间进入考试,可以减少二次参赛的作弊情况

这次题目真的很简单了,赛后看自己的排名是 28 名
因为很多人都是满分,所以同分数按时长排名
但最后获奖通知里发现自己居然是第 10 名,原来前面的那么多人都被判违规取消成绩了,啊这……

参赛经历

我个人此前的参赛经历只有力扣周赛和蓝桥杯而已

力扣竞赛积分在 2000 分出头,蓝桥杯成绩是 C/C++ B组 国二

能力马马虎虎,水平时高时低,这两次 CSDN 竞赛勉强打到十名左右

上次(第五期)是第九名,这次第十名

解题思路

读题

要读清楚题目的逻辑和设定,要求的什么问题,输入输出的格式,以及数据规模有多大

看套路

看是否用到了哪些套路
比如上次第五期最后一题就是二分的模板题,有了解的话很快就能写出来
如果能看出用到了什么套路,解题会容易许多

预估复杂度

一般认为,复杂度在 108 以内是可以通过的
那么有时可以根据数据规模的大小,来猜测要用到那种算法
而且很少有题目会卡在极限的规模

如果 n <= 109,可以估计复杂度为 O(logn),考虑二分

如果 n <= 105 或者 n <= 106,这两个是比较常见的规模,这种规模可能猜不出什么东西,因为它可以排序 O(n * logn),前缀和 O(n),动规, 记忆化搜索,并查集,等等……

如果 n <= 103,可以估计复杂度为 O(n^2),可能是二维的动态规划,或者记忆化搜索

如果 n <= 100,这个规模就很宽松了,因为理论最大可以是 O(n^4) 的复杂度,但很少会出现这样的复杂度,这时可以尝试无脑深搜

如果 n <= 25,可以估计复杂度为 O(2^n),在这个复杂度的可以考虑状压dp

如果 n <= 10,可以估计复杂度为 O(n!),n 的阶层复杂度的,肯定是有循环的深搜了

自测样例

自己写几个样例测一下,但要有针对性地写,写一些特殊地值,或者临界值

但是 CSDN 是可以随意提交地,可以先提交测测,再自己写样例找 bug

调试bug

在关键点输出一些信息,看看是否正常运行,这是最基本的操作了

如果遇到某些运行错误,但无法定位错在哪里
可以试试注释掉一半代码看能否运行,不断缩小注释的范围来定位 bug 所在的点

经验心得

算法的思路,其实大多还是套路
如果自己没有接触过题中的套路,就只能拼自己的灵活思考了

但是,套路中其实藏着各种各样的思维方式
所以,提升算法能力的最好方法就是多刷题

一来了解更多套路,之后遇见类似的题,心里已经知道怎么做了
二来开阔思维,灵活应对各类变种题

下面是一些竞赛常用的套路或思维,做题没有头绪时,可以一 一试想这些方法是否可行:

  • 二分,排序,滑动窗口,前缀和,深搜,广搜,最短路,记忆化搜索,并查集,逆向思维,贪心,动态规划,线段树,数学

算法的尽头是数学,如果有些题不能直接用一些算法套路来应对,那这极有可能是一道数学题

像上次的第五期竞赛,前两题都考察了质因数相关的点,第三题用逆向思维去考虑,可以用到深搜,也可以动态规划,第四题则是二分

但这期竞赛题目过于简单了,貌似没有用到算法相关的东西,都是一些语法层面的业务问题,大概也就课后作业的水准,我甚至已经忘记题目都是什么了……

资料分享

分享一下 y总 写的常用代码模板:

常用代码模板1——基础算法
常用代码模板2——数据结构
常用代码模板3——搜索与图论
常用代码模板4——数学知识

第六期题解

这次题目都比较简单,象征性的写一下题解吧

1. 严查枪火

X国最近开始严管枪火。 像是“ak”,“m4a1”,“skr”。都是明令禁止的。 现在小Q查获了一批违禁物品其中部分是枪支。
小Q想知道自己需要按照私藏枪火来关押多少人。 (只有以上三种枪被视为违法)

AC 代码:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

using namespace std;

int solution(int n, std::vector<std::vector<std::string>> &vec) {
    int res;
    for (auto &a : vec) {
        for (auto &s : a) {
            if (s == "ak" || s == "m4a1" || s == "skr") {
                res++;
                break;
            }
        }
    }
    return res;
}

int main() {
    int n;
    std::vector<std::vector<std::string>> vec;
    std::cin >> n;
    std::string line, token;
    for (size_t i = 0; i < n; i++) {
        std::vector<std::string> s;
        getline(std::cin >> std::ws, line);
        std::stringstream tokens(line);
        while (std::getline(tokens, token, ' ')) {
            s.push_back((token));
        }
        vec.push_back(s);
    }
    int result = solution(n, vec);
    std::cout << result << std::endl;
    return 0;
}

2. 鬼画符门

鬼画符门,每年都会统计自己宗门鬼画符消耗的数量,往年一直是大师兄管理, 但是这次鬼艺接手了, 你能帮鬼艺写一个程序统计每年消耗数量最多的鬼画符吗?

AC 代码:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include<map>

using namespace std;

std::string solution(int n, std::vector<std::vector<std::string>> &vec) {
    string res;
    int mx = -1;
    map<string, int> mp;
    for (auto &a : vec) {
        for (auto &s : a) {
            mp[s]++;
        }
    }
    for (auto &[k, v] : mp) {
        if (mx < v) {
            mx = v;
            res = k;
        }
    }
    return res;
}

int main() {
    int n;
    std::vector<std::vector<std::string>> vec;
    std::cin >> n;
    std::string line, token;
    for (size_t i = 0; i < n; i++) {
        std::vector<std::string> s;
        getline(std::cin >> std::ws, line);
        std::stringstream tokens(line);
        while (std::getline(tokens, token, ' ')) {
            s.push_back((token));
        }
        vec.push_back(s);
    }
    std::string result = solution(n, vec);
    std::cout << result << std::endl;
    return 0;
}

3. 收件邮箱

已知字符串str,str表示邮箱的不标准格式。 其中”.”会被记录成”dot”,”@”记录成”at”。 写一个程序将str转化成可用的邮箱格式。(可用格式中字符串中除了开头结尾所有”dot”,都会被转换,”at”只会被转化一次,开头结尾的不转化)

这题最麻烦,当时废了不少时间

AC 代码:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

using namespace std;

bool check_at(string &s, int i) {
    return s.length() > i + 2 && s[i] == 'a' && s[i + 1] == 't';
}

bool check_dot(string &s, int i) {
    return s.length() > i + 3 && s[i] == 'd' && s[i + 1] == 'o' && s[i + 2] == 't';
}

std::string solution(std::string str) {
    string res = "";
    res += str[0];
    bool f = false;
    for (int i = 1; i < str.size(); i++) {
        if (check_at(str, i) && !f) {
            f = true;
            res += "@";
            i += 1;
        } else if (check_dot(str, i)) {
            res += ".";
            i += 2;
        } else res += str[i];
    }
    return res;
}

int main() {
    std::string str;
    std::cin >> str;
    std::string result = solution(str);
    std::cout << result << std::endl;
    return 0;
}

4. 最长递增的区间长度

给一个无序数组,求最长递增的区间长度。如:[5,2,3,8,1,9] 最长区间 2,3,8 长度为 3

这题勉强算是个滑动窗口吧

AC 代码:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

int solution(int n, std::vector<int> &a) {
    int ans = 1;
    int len = 1;
    for (int i = 1; i < n; i++) {
        if (a[i] > a[i - 1]) len++;
        else len = 1;
        ans = std::max(ans, len);
    }
    return ans;
}

int main() {
    int n;
    std::vector<int> vec;
    std::cin >> n;
    std::string line_0, token_0;
    getline(std::cin >> std::ws, line_0);
    std::stringstream tokens_0(line_0);
    while (std::getline(tokens_0, token_0, ' ')) {
        vec.push_back(std::stoi(token_0));
    }
    int result = solution(n, vec);
    std::cout << result << std::endl;
    return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值