2019 团体程序设计天梯赛
今天模拟了一下2019年的GPLT,最后也打了个国三的分,主要是L1最后一道字符串耗费了好多时间,string的一些函数使用不熟练,但做了后面的L2发现其实L2的后两题甚至比这题还简单许多(仅细节方面)所以以后尽量不要过于死磕那一两个测试点的部分分,尽量多开题,多拿每个题的大部分测试分数。
L1 - 估值一亿的AI核心代码
模拟题,但是涉及到了字符串的替换操作。
逐个操作分析:
-
需求1:消除多余的空格,这个我们可以用stringstream来解决,细节就是消除后我们拼接的时候仍可能会需要空格,所以我们需要判断字母和数字的前面要补充一个空格用于拼接,可以用到函数isalnum(c)来判断字符c是否是字母或者数字。
-
需求2:大写变小写,直接操作即可。
-
需求3:字符替换操作,可以用string的replace函数,str.replace(a,b,ss)将字符串str的[a,a + b - 1]的字符串替换为ss(即位置a后面包括自己的b个字符用于替换),也可以写成str.replace(str.begin() + a,str.begin() + a + b,ss)。
但有个需要特别注意的地方,这里提到了独立,所以我们find到一个位置并不一定要替换,需要判断一下这个字符是不是独立的(即我们判断这个串左侧和右侧是否是非数字或字母的,即标点符号或者为空格),还需要注意的是如果没找到的话我们要设置一个额外的偏移量,避免死循环一直找这个不合法的位置,这里用到了str.find(ss,pos)即从pos位置开始再去找ss这个串。
还有一个点就是我现在换出来"I can",后面如果找"I"的时候又会把这个位置换掉,所以我们要么直接一遍输出一替换(不采用一次性替换好,直接输出答案),要么就是先把"I can"写成"A can",A这个位置随便用一个大写字母即可,因为通过操作2,大写字母已经不存在了,不会影响答案。 -
需求4:同上,需要判断独立性。
-
需求5:直接换即可。
完成。至此能够看到细节出现在替换后可能再次被替换需要变换一下,还有就是独立性的这个判断,不判断的话是有一个点过不去的,所以天梯赛题目的特点就是题干叙述的特殊性质一定是对应测试点的,一定要考虑
#include <bits/stdc++.h>
using namespace std;
int main() {
// cout << (char)('A' + 32) << '\n';
int n; cin >> n;
getchar();
while(n--) {
string s;
getline(cin,s);
stringstream ins(s);
string cur,rep;
int cnt = 0;
while(ins >> cur) {
if(!cnt || !isalnum(cur[0])) rep += cur;
else rep += " " + cur;
cnt++;
}
int m = rep.size();
for(int i = 0;i < m;i ++) {
if(rep[i] >= 'A' && rep[i] <= 'Z' && rep[i] != 'I') {
rep[i] = (char)(rep[i] + 32);
}
}
// cout << rep << "***\n";
int d = 0;//每次find的偏移量,要不会死循环的
while(rep.find("can you",d) != rep.npos) {
int p = rep.find("can you",d);
d = p + 1;
if((p == 0 && !isalnum(rep[p + 7])) || (!isalnum(rep[p - 1]) && !isalnum(rep[p + 7])))
rep.replace(p,7,"A can");//用一个不会出现的字符先替代I 因为会涉及到
// I can 也是独立的 I
}
d = 0;
while(rep.find("could you",d) != rep.npos) {
int p = rep.find("could you",d);
d = p + 1;
if((p == 0 && !isalnum(rep[p + 9])) || (!isalnum(rep[p - 1]) && !isalnum(rep[p + 9])))
rep.replace(p,9,"A could");
}
d = 0;
while(rep.find("I",d) != rep.npos) {
int p = rep.find("I",d);
d = p + 1;
if(!isalnum(rep[p - 1]) && !isalnum(rep[p + 1]))
rep.replace(p,1,"you");
}
d = 0;
while(rep.find("me",d) != rep.npos) {
int p = rep.find("me",d);
d = p + 1;
if(!isalnum(rep[p - 1]) && !isalnum(rep[p + 2]))
rep.replace(p,2,"you");
}
while(rep.find("?") != rep.npos) {
int p = rep.find("?");
rep.replace(p,1,"!");
}
while(rep.find("A") != rep.npos) {
int p = rep.find("A");
rep.replace(p,1,"I");
}
cout << s << '\n';
cout << "AI: " << rep << '\n';
}
return 0;
}
L2 - 冰岛人
是s11的冰岛人嘛(雾
这道题有很好的体现了题干信息的重要性。
因为题目说道名字不重复,那么我可以用名字唯一表示一个人。
对于一个人我们判断题目询问,需要存储它的性别和它的父亲是哪位,对于这个五代以内的判断,我们直接暴力往祖先去枚举,看两个人是否有五代以内的共同祖先,这里题目的意思是,假如A的100代祖先是B的1/2/3/4代祖先都称作五代以内,所以我们判断必须A和B的祖先都枚举到5代及以上,才能算作没有祖先。
用map存一下每个人对应的信息,信息性别和父亲可以用一个pair存一下。
外地人不涉及血缘问题。
天梯赛每年都会有考察STL使用的题目,妙啊
还有就是我感觉这样暴力枚举能被卡超时吧,可能数据没有那么极限。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n;
pair<int,string>p[N];//记录每个人的性别和父亲 1男 0女
map<string,pair<int,string> >mp;//名字是唯一的
bool check(string a,string b) {//感觉暴力做 理论上是可以卡的
for(int i = 1;a != "";i ++,a = mp[a].second) {
string T = b;
for(int j = 1;T != "";j ++,T = mp[T].second) {
if(j >= 5 && i >= 5)
return true;
if(a == T)
return false;
}
}
return true;
}
int main() {
cin >> n;
for(int i = 1;i <= n;i ++) {
string a,b; cin >> a >> b;
if(b[b.size() - 1] == 'n') {//男
mp[a] = {1,b.substr(0,b.size() - 4)};
} else if(b[b.size() - 1] == 'r') {
mp[a] = {0,b.substr(0,b.size() - 7)};
} else {//外地人
mp[a] = {b[b.size()-1] == 'm' ? 1 : 0,""};
}
}
int m; cin >> m;
while(m--) {
string s1,s2,s3,s4;
cin >> s1 >> s2 >> s3 >> s4;
if(mp.find(s1) == mp.end() || mp.find(s3) == mp.end()) {
cout << "NA\n";
} else {
if(mp[s1].first == mp[s3].first) {
cout << "Whatever\n";
} else {
if(check(s1,s3)) {
cout << "Yes\n";
} else {
cout << "No\n";
}
}
}
}
return 0;
}