目录
A-1 The Winner over Squares and Primes(分数 20)
前言:
本套题的难度介于2023夏季和2023秋季之间,主要是2和4有点麻烦,第2题容易超时。整体来说还好。
A-1 The Winner over Squares and Primes(分数 20)
题目:
This is about a game of fighting all the squrare numbers and prime numbers.
At the very beginning, N people are sitting in N seats, and the seats are numbered from 1 to N, from left to right. Then for all the seats with their numbers being squares (such as 1, 4, 9, 16, ...), those people sitting in must leave, and everyone else must shift toward left so that there is no empty seat between any of them. If there are more than one people left, the game continues, but instead of square numbers, this round will let everyone sitting in the prime seats leave, and then the rest of them will shift to fill the empty seats again.
The game continues with checking the square seats and prime seats alternatively, until there is only one winner left. You are supposed to tell the initial seat number for this winner.
Input Specification:
Each input file contains one test case, in which a positive integer N (≤105) is given.
Output Specification:
For each test case, print in a line the initial seat number for this winner.
Sample Input:
10
Sample Output:
6
Hint:
Round 1: People sitting in square seats 1, 4, and 9 will leave. The initial seat numbers for the rest of them sitting from 1 to 7 are 2, 3, 5, 6, 7, 8, 10.
Round 2: People sitting in prime seats 2, 3, 5, and 7 will leave. The initial seat numbers for the rest of them sitting from 1 to 3 are 2, 6, 8.
Round 3: People sitting in square seat 1 will leave. The initial seat numbers for the rest of them sitting from 1 to 2 are 6, 8.
Round 4: People sitting in prime seat 2 will leave. The initial seat numbers for the final winner is 6.
思路:
用一个数组a存储,然后从头遍历,若该不是素数或者该不是平方数,那么就赋给新数组b,最后a=b,重复上述步骤,直到最后数组只有一个数为止。
代码:
#include<bits/stdc++.h>
using namespace std;
const int max_l = 100010;
vector<int> p;
int N;
bool check(int n, bool k)
{
if (k){
if (n == 1) return 0;
else {
for (int i = 2;i <= sqrt(n);i++){
if (n % i == 0) return 0;
}
return 1;
}
}
else{
int i = 1, sum = 1;
while (sum <= n){
if (sum == n)
return 1;
else{
i++;
sum = pow(i, 2);
}
}
return 0;
}
}
int main()
{
cin >> N;
for (int i = 0;i < N;i++)
p.push_back(i + 1);
bool tag = 0;
while (p.size()>1){
vector<int> t;
for (int i = 1;i <= p.size();i++){
if (!check(i, tag)){
t.push_back(p[i - 1]);
}
}
p = t;
tag = !tag;
}
cout << p[0];
}
A-2 LRU-K(分数 25)
题目:
Least Recently Used (LRU) cache scheme is to remove the least recently used frame (the one hasn't been used for the longest amount of time) when the cache is full and a new page is referenced which is not there in cache.
LRU-K is a variant of the LRU algorithm, where K represents the number of recent uses. LRU can be considered as LRU-1. Unlike LRU, the LRU-K requires the maintenance of two different queues (for historical access and cache). The data in the historical access queue is not moved to the cache queue until the data is hit K times.
For example, assuming that the length of both queues is 5, and the memory is initialized to be empty. LRU-2 is used to process the data sequence in order: 9,5,6,7,8,3,8,9,5,9,8,3,4,7,5,6. The changes of the historical access queue and the cache queue are shown in the following table:
Data Access | Historical Aaccess Queue | Cache Queue |
---|---|---|
9,5,6,7,8 | 9,5,6,7,8 | Empty |
3 | 5,6,7,8,3 | Empty |
8 | 5,6,7,3 | 8 |
9 | 5,6,7,3,9 | 8 |
5 | 6,7,3,9 | 8,5 |
9 | 6,7,3 | 8,5,9 |
8 | 6,7,3 | 5,9,8 |
3 | 6,7 | 5,9,8,3 |
4 | 6,7,4 | 5,9,8,3 |
7 | 6,4 | 5,9,8,3,7 |
5 | 6,4 | 9,8,3,7,5 |
6 | 4 | 8,3,7,5,6 |
Your job is to implement this LRU-K cache scheme.
Input Specification:
Each input file contains one test case. For each case, the first line gives 3 positive integers: K (≤5), N (≤104) and M (≤105) which are the number of hits for cache, the size of the queues (assuming both queues have the same size) and the number of referenced page ID's. Then M referenced page ID's are given in the next line. A page ID is a number in the range [1,2×104]. All the numbers in a line are separated by a space.
Output Specification:
For each test case, output in the first line the page ID's in the historical access queue, and in the second line, those in the cache queue. The ID's are ordered from front to rear of each queue. All the numbers in a line must be separated by 1 space, and there must be no extra space at the beginning or the end of the line. In case that a queue is empty, output -
in a line instead.
Sample Input 1:
2 5 17
9 5 6 7 8 3 8 9 5 9 8 3 4 7 5 6 9
Sample Output 1:
4 9
8 3 7 5 6
Sample Input 2:
3 5 10
9 5 6 7 8 3 8 9 5 9
Sample Output 2:
7 3 8 5 9
-
思路:
我最初的思路是用两个双端队列模拟,结果最后有两个测试点超时:
其实本题中涉及大量查询和删除,所以最好使用map或set,但是使用这些的话,我们怎么能让这个按照题意得顺序输出呢?其实可以引入一个时间戳,我们以输入数据的下标i作为输入数据的时间戳,然后重载自己定义的struct的<运算,使用时间戳排序代替set默认的排序,然后应该就可以过了。
代码:
由于这道题当时没过,现在也不能提交了,因此大家可以参考下面这个代码:如果这个能AC的话,麻烦大家在评论区说一下。
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
struct no{
int key, t;
bool operator<(const no &A)const{
return t < A.t;
}
};
set<no> cache, hist;
int rect[N], recn[N];
vector<int> ans;
int main(){
int k, n, m, a; cin>>k>>n>>m;
for(int i = 1; i <= m; i ++){
scanf("%d", &a);
if(cache.find({a, rect[a]}) != cache.end()){
cache.erase({a, rect[a]});
cache.insert({a, i});
rect[a] = i;
}
else{
if(hist.find({a, rect[a]}) == hist.end()){
recn[a] = 1;
rect[a] = i;
hist.insert({a, i});
if(hist.size() > n){
for(auto j : hist){
hist.erase(j);
recn[j.key] = 0, rect[j.key] = 0;
break;
}
}
}
else{
hist.erase({a, rect[a]});
hist.insert({a, i});
recn[a] ++, rect[a] = i;
if(recn[a] == k){
cache.insert({a, rect[a]});
if(cache.size() > n){
for(auto j : cache){
cache.erase(j);
recn[j.key] = 0, rect[j.key] = 0;
break;
}
}
hist.erase({a, i});
}
}
}
}
if(hist.size() == 0) printf("-\n");
else{
for(auto i : hist) ans.push_back(i.key);
for(int i = 0; i < ans.size() - 1; i++) printf("%d ", ans[i]);
printf("%d\n", ans.back());
}
if(cache.size() == 0) printf("-");
else{
for(auto i : cache) ans.push_back(i.key);
for(int i = 0; i < ans.size() - 1; i++) printf("%d ", ans[i]);
printf("%d", ans.back());
}
return 0;
}
附上一个当时写的又臭又长的超时代码:
#include<bits/stdc++.h>
using namespace std;
deque<int> a, b;
int v[100010], K, N, M;
int main()
{
cin >> K >> N >> M;
for (int i = 0;i < M;i++) cin >> v[i];
int pos = 0;
map<int, int> ppp;
while (pos < M)
{
int t = v[pos], def = 1;
pos++;
for (int i = 0;i < b.size();i++)
{
if (t == b[i])
{
def = 0;
b.erase(b.begin() + i);
b.push_back(t);
break;
}
}
if (def)
{
int tag = 1;
for (int i = 0;i < a.size();i++)
{
if (t == a[i])
{
ppp[t]++;
if (ppp[t] == K)
{
tag = 0;
a.erase(a.begin() + i);
ppp[t] = 0;
int abc = 1;
for (int j = 0;j < b.size();j++)
{
if (b[j] == t)
{
abc = 0;
b.erase(b.begin() + j);
b.push_back(t);
break;
}
}
if (abc)
{
if (b.size() == N)
b.pop_front();
b.push_back(t);
}
}
else {
tag = 0;
a.erase(a.begin() + i);
a.push_back(t);
}
break;
}
}
if (tag)
{
if (a.size() == N)
{
ppp[a.front()] = 0;
a.pop_front();
}
a.push_back(t);
ppp[t]++;
}
}
}
if (a.size())
{
for (int i = 0;i < a.size();i++)
{
if (i != 0)
cout << " ";
cout << a[i];
}
}
else
cout << "-";
cout << endl;
if (b.size())
{
for (int i = 0;i < b.size();i++)
{
if (i != 0)
cout << " ";
cout << b[i];
}
}
else
cout << "-";
}
A-3 K Vertex(分数 25)
题目:
Given a directed graph, a K-vertex is a vertex of which the out degree is larger than the indegree. For example, the vertices a
and b
in the figure are K-vertices.
Your job is to list all the K-vertices in a given graph.
Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers: N (≤200) and M, which are the number of vertices and the number of edges, respectively. Then M lines follow, each gives a directed edge <v1
, v2
> in the format:
v1 v2
Here we assume that all the vertices are numbered from 0 to N−1. It is guaranteed that v1
is never the same as v2
.
Finally a line of N strings is given, where the i-th string corresponds to the key of the i-th vertex (i=0,⋯,N−1). Each string consists of no more than 2 lower-cased English letters.
Output Specification:
Output the keys of all the K-vertices, each occupies a line, in alphabetical order. It is guaranteed that there is at least one output.
Sample Input:
4 5
0 1
2 1
3 1
2 0
3 2
c d b a
Sample Output:
a
b
思路:
第三题就很简单了,甚至不需要dfs,模拟即可
代码:
#include<bits/stdc++.h>
using namespace std;
map<string, pair<int, int>> m;//ru,chu
vector<pair<int, int>> v;
vector<string> d(210);
int main()
{
int N, M;
cin >> N >> M;
while (M--)
{
int a, b;
cin >> a >> b;
v.push_back(make_pair(a, b));
}
for (int i = 0;i < N;i++)
cin >> d[i];
for (int i = 0;i < v.size();i++)
{
m[d[v[i].first]].second++;
m[d[v[i].second]].first++;
}
vector<string> r;
for (auto i : m)
{
if (i.second.first < i.second.second)
r.push_back(i.first);
}
sort(r.begin(), r.end());
for (auto i : r)
cout << i << endl;
}
A-4 Tree of Love(分数 30)
题目:
If a binary tree has its left and right subtrees perfectly symmetric. And more, if from left to right, the depths of leaves are first in increasing (or non-decreasing) then decreasing (or non-increasing), then again increasing (or non-decreasing), and finally decreasing (or non-increasing) order, then the shape of this tree looks like a heart (as shown by the above figure), and hence is called "Tree of Love".
Given the inorder and postorder traversal sequences of a binary tree, your job is to construct this tree and test if it is a tree of love, and output its outer contour(外轮廓). "Outer contour" consists of nodes visited from the root, along the left most path to a leaf, then all the leaves from left to right, and finally back to the root along the right most path.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (<100), which is the number of nodes in the tree. Then the next two lines each contains N positive keys as the inorder and postorder traversal sequences, respectively. All the keys are distinct integers no more than 103. The numbers in a line are separated by spaces. It is guaranteed that a unique binary tree can be constructed from the input.
Output Specification:
For each test case, if the tree is a tree of love, output Yes
in the first line, or No
if not. Then output the outer contour in the second line.
All the numbers in a line must be separated by 1 space, and there must be no extra space at the beginning or the end of the line.
Sample Input 1:
27
5 4 6 22 3 23 7 20 2 21 8 18 9 1 10 19 11 24 17 25 12 26 16 27 13 15 14
5 6 22 4 7 23 20 3 8 21 9 18 2 10 11 24 19 12 26 25 13 27 14 15 16 17 1
Sample Output 1:
Yes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Sample Input 2:
11
4 8 10 2 5 1 6 3 9 11 7
10 8 4 5 2 6 11 9 7 3 1
Sample Output 2:
No
1 2 4 10 5 6 11 7 3
Hint for Sample 2:
The answer is No
because the tree is not symmetric. It would be Yes
if we swap 9 and 11 in the inorder sequence.
思路:
先建树,然后一个dfs得到所有结点的深度,接着就需要得到外框序列;对于外框序列,可以对根的左子树进行先序遍历,到第一个叶结点停止;然后再对根的左子树进行先序遍历,只获取叶结点;然后再对右子树重复上述操作(将先序改为后序),最后拼接这四段即可。
还有一种方法,我们可以直观地想到,外框是由每一层的最左和最右以及最下方的叶子结点序列组成,所以可以由层序得到每一层的最左和最右结点,然后再对根的左子树进行前序遍历,对根的右子树进行后序遍历即可,注意判断条件是(当该结点为叶结点或者该结点为每一层的最左或者最右的结点)
代码:
#include<bits/stdc++.h>
using namespace std;
const int max_l = 110;
int N;
int in[max_l], post[max_l];
struct node {
int l=-1, r=-1;
}v[1010];
int d[1010], c[1010];
vector<int> r, h;
void dfs(int cur, int dep)
{
d[cur] = dep;
if (cur==-1) return;
dfs(v[cur].l, dep + 1);
dfs(v[cur].r, dep + 1);
}
void ceng(int root)
{
int tag = 1;
queue<int> q;
q.push(root);
while (q.size())
{
int t = q.front();
if (tag == pow(2, d[t]) || tag == pow(2, d[t] + 1) - 1)
c[t] = 1;
tag++;
q.pop();
if(v[t].l!=-1) q.push(v[t].l);
if (v[t].l != -1) q.push(v[t].r);
}
}
void pre(int cur)
{
if (cur == -1) return;
if ((v[cur].l == -1 && v[cur].r == -1) || c[cur] == 1)
{
if (v[cur].l == -1 && v[cur].r == -1)
h.push_back(cur);
r.push_back(cur);
}
pre(v[cur].l);
pre(v[cur].r);
}
void pos(int cur)
{
if (cur == -1) return;
pos(v[cur].l);
pos(v[cur].r);
if ((v[cur].l == -1 && v[cur].r == -1) || c[cur] == 1)
{
if (v[cur].l == -1 && v[cur].r == -1)
h.push_back(cur);
r.push_back(cur);
}
}
int build(int h1, int t1, int h2, int t2)
{
if (h1 > t1 || h2 > t2) return -1;
int root = post[t2];
int i;
for (i = h1;in[i] != root;i++);
v[root].l = build(h1, i - 1, h2, i - 1 + h2 - h1);
v[root].r = build(i + 1, t1, t2 + i - t1, t2 - 1);
return root;
}
int main()
{
cin >> N;
for (int i = 0;i < N;i++)cin >> in[i];
for (int i = 0;i < N;i++)cin >> post[i];
int root = build(0, N - 1, 0, N - 1);
dfs(root, 0);
ceng(root);
r.push_back(root);
pre(v[root].l);
pos(v[root].r);
int tag = 1, last = d[h[0]];
for (int i = 1;i < h.size();i++)
{
if (tag == 1 && d[h[i]] >= last) tag = 2;
else if (tag == 2 && d[h[i]] <= last) tag = 3;
else if (tag == 3 && d[h[i]] >= last) tag = 4;
else if (tag == 4 && d[h[i]] <= last) tag = 5;
}
if (tag == 5) cout << "Yes" << endl;
else cout << "No" << endl;
for (int i = 0;i < r.size();i++)
{
if (i)
cout << " ";
cout << r[i];
}
}
当然也可以参考别人的博客的解法: