2022年CCCC天梯赛
静静的推荐
思路:
模拟应该会超时,首先可以确定的是cc超过175且pat超过s的人一定会被录取,所以这些直接加到答案里,剩下的就看各个分数有多少人,因为每个分数每次录一个最多录k次,所以每个分数最多录取的人数为min(cnt[i], k),加起来就是答案
#include <bits/stdc++.h> using namespace std; int n, k, s; int cnt[300]; int main() { cin >> n >> k >> s; int res = 0; for(int i = 1; i <= n; i ++ ) { int t, p; cin >> t >> p; if(t >= 175) { if(p >= s) res ++ ; else cnt[t] ++ ; } } for(int i = 175; i <= 290; i ++ ) res += min(cnt[i], k); cout << res << endl; return 0; }
插松枝
思路:
大模拟,先考虑栈再考虑队列,在队列中都不满足情况还有栈和队列都不满足情况都要break
#include <bits/stdc++.h> using namespace std; int main() { int n, m, k; cin >> n >> m >> k; queue<int>q; stack<int>st; for(int i = 1; i <= n; i ++ ) { int x; cin >> x; q.push(x); } while(q.size() || st.size()) { int cnt = 0, last = 100; bool first = true; while(cnt < k) { if(st.size() && st.top() <= last) { if(first) { first = false; cout << st.top(); } else cout << ' ' << st.top(); last = st.top(); st.pop(); cnt ++ ; } else if(q.size()) { int t = q.front(); if(t <= last) { if(first) { cout << t; first = false; } else cout << ' ' << t; last = t; q.pop(); cnt ++ ; } else if(st.size() < m) { st.push(t); q.pop(); } else break; } else break; } cout << endl; } return 0; }
老板的作息表
思路:
结构体或pair排序,这里直接pair里存两个string表示起始时间和结束时间方便一些,然后直接排序,遍历找不连续区间。有两个坑点,第一个是最后的到23:59::59这个时间段,第二个是刚开始的00:00:00这个时间。
#include <bits/stdc++.h> using namespace std; const int N = 50010; int main() { int n; cin >> n; vector<pair<string, string>>v; for(int i = 0; i < n; i ++ ) { string a, b, c; cin >> a >> b >> c; v.push_back({a, c}); } sort(v.begin(), v.end()); string last = "-1"; for(auto s: v) { if(last == "-1") { if(s.first != "00:00:00") cout << "00:00:00" << " - " << s.first << endl; last = s.second; } else { if(last == s.first) last = s.second; else { cout << last << " - " << s.first << endl; last = s.second; } } } if(last != "23:59:59") cout << last << " - " << "23:59:59" << endl; return 0; }
龙龙送外卖
思路:
假设我们每个外面送完都回到根节点,那假设我们一共遍历了sum条边,我们走的距离总和就是2*sum,那因为我们不用每次都回到根节点,所以我们假设最后一次送完没有回到根节点,这个结点到根节点的距离为d,那总路径就是2*sum-d,要求总路径最小,所以我们让d最大即可,即最后一次停在了离根节点最远的地方
#include <bits/stdc++.h> using namespace std; const int N = 100010; int n, m; int d[N]; int fa[N]; int sum, mx; int dfs(int u) { if(fa[u] == -1 || d[u]) return d[u]; // 到根节点了或u被搜过了 sum ++ ; // 边数加一,因为没有搜过 d[u] = dfs(fa[u]) + 1; return d[u]; } int main() { cin >> n >> m; for(int i = 1; i <= n; i ++ ) cin >> fa[i]; while(m -- ) { int x; cin >> x; mx = max(mx, dfs(x)); cout << sum * 2 - mx << endl; } return 0; }
大众情人
思路:
首先用floyd求出所有最短距离,然后根据题意,先求出某个人的每个人对他/她最无感的距离mx,即最大值,然后由于大众情人是其中1/mx最大,所以最后所求的是所有mx的最小值,最后遍历一遍谁的mx等于这个最小值就是答案
#include <bits/stdc++.h> using namespace std; const int N = 510; int n; char sex[N]; int d[N][N]; int main() { cin >> n; memset(d, 0x3f, sizeof d); for(int i = 1; i <= n; i ++ ) d[i][i] = 0; for(int i = 1; i <= n; i ++ ) { cin >> sex[i]; int k; cin >> k; while(k -- ) { int id, dist; scanf("%d:%d", &id, &dist); d[i][id] = dist; } } for(int k = 1; k <= n; k ++ ) for(int i = 1; i <= n; i ++ ) for(int j = 1; j <= n; j ++ ) d[i][j] = min(d[i][j], d[i][k] + d[k][j]); for(auto c: string("FM")) { int mn = 0x3f3f3f3f; for(int i = 1; i <= n; i ++ ) if(sex[i] == c) { int mx = 0; for(int j = 1; j <= n; j ++ ) if(sex[i] != sex[j]) mx = max(mx, d[j][i]); // 最无感的距离 mn = min(mn, mx); // 1/d最大,所以d要最小 } bool first = true; for(int i = 1; i <= n; i ++ ) if(sex[i] == c) { int mx = 0; for(int j = 1; j <= n; j ++ ) if(sex[i] != sex[j]) mx = max(mx, d[j][i]); if(mx == mn) { if(first) { cout << i; first = false; } else cout << ' ' << i; } } cout << endl; } return 0; }