前言、
又是一年算法公选课,与去年不同的是今年学了一些纯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++新版本出了越来越多的语法糖,存在即合理。新语法糖肯定有优秀的地方,我们在书写代码的时候应该尽可能多地使用新语法