SRM151 DIV2

最近开始拍 TC 的陈题,这应该算是第二套 AK 的题目了吧,题目不是很难,很适合练习拍代码的速度。。。

250 分:Prefix Code

这题单纯的暴力过的,枚举第 ii 个串是不是其他串的前缀,利用一个函数直接判定,这样的时间复杂度为 O(n2)O(n^2) 对于 n50n \leq 50 的数据来说完全没有问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class PrefixCode {
public:
bool check(string str, string sub) {
int len = str.length();
int sublen = sub.length();
if (sublen > len) return false;
if (str.substr(0, sublen) == sub) return true;
return false;
}
string isOne(vector<string> words) {
int n = words.size();
string ret;
char str[100];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) continue;
if (check(words[j], words[i])) {
ret = "No, ";
sprintf(str, "%d", i);
ret += str;
return ret;
}
}
}
ret = "Yes";
return ret;
}
};

500 分:Birthday

判断当前时间之后第一个过生日的人的日期,简单的排序即可,注意人名都是字母,用 0000 表示当前的时间对应的人名,这样把全部的人加上这个哨兵总共 n+1n+1 个元素进行排序,最后输出哨兵的后一位元素,查找是线性的查找,总共的复杂度为 O(nlogn)O(nlogn),即排序的复杂度。

注意当哨兵是最后一个的时候输出第一个元素,这里取模来直接达到这个效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
struct Node {
string name;
int month;
int day;
bool operator<(const Node& node) const {
if (month != node.month)
return month < node.month;
else
return day < node.day;
}
};
class Birthday {
public:
string getNext(string date, vector<string> bir) {
Node node;
vector<Node> v;
char str[100];
int n;
int pos;
string a;
v.clear();
node.name = "0000";
node.month = (date[0] - '0') * 10 + date[1] - '0';
node.day = (date[3] - '0') * 10 + date[4] - '0';
v.push_back(node);
n = bir.size();
for (int i = 0; i < n; i++) {
int len = bir[i].length();
node.month = (bir[i][0] - '0') * 10 + bir[i][1] - '0';
node.day = (bir[i][3] - '0') * 10 + bir[i][4] - '0';
node.name = bir[i].substr(6, len - 6);
v.push_back(node);
}
sort(v.begin(), v.end());
for (int i = 0; i < n + 1; i++)
if (v[i].name == "0000") {
pos = i;
break;
}
pos = (pos + 1) % v.size();
sprintf(str, "%02d/%02d", v[pos].month, v[pos].day);
a = str;
return a;
}
};

1000 分:Merge Sort

叫你模拟归并排序的过程,输出比较次数,直接手写归并排序,遇到比较就计数器加 1,模拟完就返回结果,注意题目要求的划分方式和合并方式和我们一般写的代码有差距,如果两个子数组的个数不同,那么要求前一个的元素个数小于后面的元素个数,当两个子数组的头元素相等的时候,将两个元素都放入父亲结点对应的数组,这样比较次数为 1 次,而不是先随便放入一个,剩下一个和后面的元素比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class MergeSort {
public:
int ret;
int a[100];
void Merge(int p, int q, int r) {
int n1 = q - p + 1;
int n2 = r - q;
vector<int> left;
vector<int> right;
for (int i = 0; i < n1; i++) left.push_back(a[p + i]);
for (int j = 0; j < n2; j++) right.push_back(a[q + j + 1]);
int i = 0, j = 0, k = p;
while (i < n1 && j < n2) {
ret++;
if (left[i] < right[j]) {
a[k++] = left[i];
i++;
} else if (left[i] == right[j]) {
a[k++] = left[i];
a[k++] = right[j];
i++;
j++;
} else {
a[k++] = right[j];
j++;
}
}
if (i == n1) {
for (; j < n2; j++) a[k++] = right[j];
} else {
for (; i < n1; i++) a[k++] = left[i];
}
}
void Sort(int p, int r) {
if (p < r) {
int q = (p + r) >> 1;
int n1 = q - p + 1;
int n2 = r - q;
if (n1 > n2) q--;
Sort(p, q);
Sort(q + 1, r);
Merge(p, q, r);
}
}
int howManyComparisons(vector<int> num) {
int len = num.size();
ret = 0;
for (int i = 0; i < len; i++) a[i] = num[i];
Sort(0, len - 1);
return ret;
}
};

总结

这套题适合用于提高编码能力,要求能在最短的时间内模拟出结果,三题应该都算是模拟题,第二题的排序可以用系统库函数直接处理,无需手写。