自学内容网 自学内容网

ZISUOJ 2024算法基础公选课练习一(1)

前言、

        又是一年算法公选课,与去年不同的是今年学了一些纯C++(而不是带类的C)

一、我的C++模板

1.1 模板1

#include <bits/stdc++.h>
using i64 = long long;

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    return 0;
}

1.2 模板2

#include <bits/stdc++.h>
using i64 = long long;

void solve() {
    
}
int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    int t = 1;
    //如果有多组数据,则放开下一行的注释
    // std::cin >> t;
    while(t--) {
        solve();
    }
    return 0;
}

 

二、题目总览

三、具体题目

        3.1 问题 A: 删数问题(Tan1):

思路:

        用贪心算法(属于不是很容易察觉的那种)。跑k次循环,每次循环找出第一个逆序对,此时需要删去的就是逆序对中的第一个数(较大的那个);如果找不到逆序对,那么删除最后一个数。另外,特判出现前导零的情况,既可以用string的erase()方法,也可以用reverse()函数反转字符串,再使用pop_back()函数(主要是因为没有pop_front()函数,猜测string是拿vector实现的,而不是deque)。

参考代码1:

#include <bits/stdc++.h>
using i64 = long long;

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    std::string a;int k;
    std::cin >> a >> k;
    for(int i = 0;i<k;i++) {
        int idx = 0;
        while(idx<a.size()-1&&a[idx]<=a[idx+1]) idx++;
        if(idx!=a.size()-1) {
            a.erase(idx,1);
        }else {
            a.erase(a.size()-1,1);
        }
    }
    while(a.front()=='0'&&a.size()>1) {
        a.erase(0,1);
    }
    std::cout << a << '\n';

    return 0;
}

参考代码2:

#include <bits/stdc++.h>
using i64 = long long;

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    std::string a;int k;
    std::cin >> a >> k;
    for(int i = 0;i<k;i++) {
        int idx = 0;
        while(idx<a.size()-1&&a[idx]<=a[idx+1]) idx++;
        if(idx!=a.size()-1) {
            a.erase(idx,1);
        }else {
            a.erase(a.size()-1,1);
        }
    }
    std::string ans = a;
    std::reverse(ans.begin(),ans.end());
    while(ans.back()=='0'&&ans.size()>1){
        ans.pop_back();
    }
    std::reverse(ans.begin(),ans.end());
    std::cout << ans << '\n';

    return 0;
}

        3.2 问题 B: 输出亲朋字符串:

思路:

        没啥好说的,模拟一下就行,如果打算直接在原字符串上修改,那么需要暂存第一个字符

参考代码:

#include <bits/stdc++.h>
using i64 = long long;

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    std::string s;
    std::getline(std::cin,s);
    char tmp = s[0];
    for(int i = 0;i<s.size();i++) {
        if(i!=s.size()-1) {
            s[i]+=s[i+1];
        }else {
            s[i]+=tmp;
        }
    }
    std::cout << s << '\n';

    return 0;
}

        3.3 问题 C: 密钥加密:

思路:

        注意题中的两个模运算,因为字符串可能存在空格,所以读数据用getline()来读

参考代码:

这里有两个小技巧

 1.字符'0'到'9'转数字,我们可以直接异或48,同理,数字转字符'0'到'9'也可以直接异或48得到

  2.string下标从0开始,我们可以让它的前面拼接一个字符(通常是空格),这样它有意义的字符下标就从1开始,当然输出的时候记得把第一个字符去掉再输出

#include <bits/stdc++.h>
using i64 = long long;

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    std::string key,str;
    while(std::getline(std::cin,key)&&std::getline(std::cin,str)) {
        int len_key = key.size();
        int len_str = str.size();

        std::vector<int> real_key;
        real_key.emplace_back(key[len_key-1]^48);
        for(int i = 0;i<len_key-1;i++) {
            real_key.emplace_back(key[i]^48);
        }

        str = " "+str;
        for(int i = 1;i<=str.size();i++) {
            str[i] = str[i]+real_key[i%len_key];
            str[i] = str[i]>122?str[i]-91:str[i];
        }
        str.erase(0,1);

        std::cout << str << '\n';
    }

    return 0;
}

        3.4 问题 D: 排列对称串:

思路:

如果一个字符串前后反转还等于反转前的值,那么它就是对称的字符串,把对称的字符串放进vector,然后排序一下,排序可以写cmp()函数,也可以用C++11的语法糖-匿名函数(我下面的代码是拿匿名函数写的),最后输出vector的内容即可

参考代码:

小技巧:

基于范围的for循环也是C++11的新语法糖,可以遍历一个容器,减少代码书写量

#include <bits/stdc++.h>
using i64 = long long;

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    std::vector<std::string> v;
    std::string str;

    while(std::getline(std::cin,str)) {
        std::string reverse_str = str;
        std::reverse(reverse_str.begin(),reverse_str.end());
        if(reverse_str==str) {
            v.emplace_back(str);
        }
    }

    std::sort(v.begin(),v.end(),[&](const std::string &s1,const std::string &s2)->bool {
        if(s1.size()!=s2.size()) return s1.size()<s2.size();
        return s1<s2;
    });

    for(auto &vi:v) {
        std::cout << vi << '\n';
    }

    return 0;
}

3.5 问题 E: 《庆余年》之四大宗师:

思路:

利用哈希表先把每个人的积分算出来,然后拷贝到vector中排序(因为哈希表不支持排序),然后根据要求排序,排序好后输出即可

参考代码:

小技巧:

拷贝可以用copy()函数实现,也可以写一个for循环,然后把数据emplace_back进vector

#include <bits/stdc++.h>
using i64 = long long;
using psi = std::pair<std::string,int>;

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    std::unordered_map<std::string,int> mp;
    std::string player1,player2,result;

    for(int t = 0;t<6;t++) {
        std::cin >> player1 >> player2 >> result;
        if(result=="S") {
            mp[player1]+=3;
        }else if(result=="F") {
            mp[player2]+=3;
        }else {
            mp[player1]+=1;
            mp[player2]+=1;
        }
    }

    std::vector<psi> v(mp.size());
    std::copy(mp.begin(),mp.end(),v.begin());

    std::sort(v.begin(),v.end(),[&](const psi &p1,const psi &p2)->bool {
        if(p1.second!=p2.second) return p1.second>p2.second;
        return p1.first<p2.first;
    });

    for(auto &player:v) {
        std::cout << player.first << '\n';
    }

    return 0;
}

后记:

我写了很多C++11的语法糖,C++新版本出了越来越多的语法糖,存在即合理。新语法糖肯定有优秀的地方,我们在书写代码的时候应该尽可能多地使用新语法


原文地址:https://blog.csdn.net/Beau_Will/article/details/143581098

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!