L2阶段题目(25分)
L2-045 堆宝塔
堆宝塔游戏是让小朋友根据抓到的彩虹圈的直径大小,按照从大到小的顺序堆起宝塔。但彩虹圈不一定是按照直径的大小顺序抓到的。聪明宝宝采取的策略如下:
- 首先准备两根柱子,一根 A 柱串宝塔,一根 B 柱用于临时叠放。
- 把第 1 块彩虹圈作为第 1 座宝塔的基座,在 A 柱放好。
将抓到的下一块彩虹圈 C 跟当前 A 柱宝塔最上面的彩虹圈比一下,如果比最上面的小,就直接放上去;否则把 C 跟 B 柱最上面的彩虹圈比一下: - 如果 B 柱是空的、或者 C 大,就在 B 柱上放好;
- 否则把 A 柱上串好的宝塔取下来作为一件成品;然后把 B 柱上所有比 C 大的彩虹圈逐一取下放到 A 柱上,最后把 C 也放到 A 柱上。
重复此步骤,直到所有的彩虹圈都被抓完。最后 A 柱上剩下的宝塔作为一件成品,B 柱上剩下的彩虹圈被逐一取下,堆成另一座宝塔。问:宝宝一共堆出了几个宝塔?最高的宝塔有多少层?
解题思路
用C++中的STL里面的stack然后按题意模拟即可。
参考代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using ld = long double;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
void solve(){
stack<int> s1,s2;
int n;
cin >> n;
int ans1 = 0,ans2 = 0;
int x;
cin >> x;
s1.push(x);
for(int i = 2;i <= n;i ++){
int x;
cin >> x;
int t = s1.top();
if(x < t){
s1.push(x);
}else{
if(s2.empty()){
s2.push(x);
}else{
int tt = s2.top();
if(x > tt){
s2.push(x);
}else{
int cnt = 0;
while(!s1.empty()){
s1.pop();
cnt ++;
}
ans1 ++;
ans2 = max(ans2,cnt);
while(!s2.empty()){
int ee = s2.top();
if(ee > x){
s1.push(ee);
}else{
break;
}
s2.pop();
}
s1.push(x);
}
}
}
}
int cnt = 0;
while(!s1.empty()){
s1.pop();
cnt ++;
}
if(cnt){
ans1 ++;
ans2 = max(ans2,cnt);
}
cnt = 0;
while(!s2.empty()){
s2.pop();
cnt ++;
}
if(cnt){
ans1 ++;
ans2 = max(ans2,cnt);
}
cout << ans1 << " " << ans2;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin >> t;
while(t --){
solve();
}
}
L2-046 天梯赛的赛场安排
天梯赛使用 OMS 监考系统,需要将参赛队员安排到系统中的虚拟赛场里,并为每个赛场分配一位监考老师。每位监考老师需要联系自己赛场内队员对应的教练们,以便发放比赛账号。为了尽可能减少教练和监考的沟通负担,我们要求赛场的安排满足以下条件:
- 每位监考老师负责的赛场里,队员人数不得超过赛场规定容量 C;
- 每位教练需要联系的监考人数尽可能少 —— 这里假设每所参赛学校只有一位负责联系的教练,且每个赛场的监考老师都不相同。
为此我们设计了多轮次排座算法,按照尚未安排赛场的队员人数从大到小的顺序,每一轮对当前未安排的人数最多的学校进行处理。记当前待处理的学校未安排人数为 n:
- 如果 n≥C,则新开一个赛场,将 C 位队员安排进去。剩下的人继续按人数规模排队,等待下一轮处理;
- 如果 n<C,则寻找剩余空位数大于等于 n 的编号最小的赛场,将队员安排进去;
- 如果 n<C,且找不到任何非空的、剩余空位数大于等于 n 的赛场了,则新开一个赛场,将队员安排进去。
由于近年来天梯赛的参赛人数快速增长,2023年超过了 480 所学校 1.6 万人,所以我们必须写个程序来处理赛场安排问题。
解题思路
使用优先队列priority_queue
按学校的队员人数从大到小排序然后根据题目条件即可。
值得一提的是,优先队列该如何重载< 符号
来定义排序规则。
首先我们假设这里的队员人数为count
,按count
从大到小排序结构体的话,就是要当a.count ? b.count
时使得结构体a < b
。?
就是我们要确定的符号(<
还是 >
)。因为优先队列是按照优先级来排序的,优先级高的会在前面
,所以这里应该是a.count < b.count
。意思就是count
更小的结构体优先级更低会排在后面,那么count
更大的优先级自然也就更高了排在前面了。那么这里的重载 <
参考写法如下:
bool operator <(const node& a)const{
return count < a.count;
}
参考代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using ld = long double;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
struct node{
int code;
string name;
int count;
bool operator <(const node& a)const{
return count < a.count;
}
};
void solve(){
priority_queue<node> q;
int n,c;
cin >> n >> c;
vector<int> ans(n + 1);
map<int,string> mp;
int sum = 0;
for(int i = 1;i <= n;i ++){
string s;
int k;
cin >> s >> k;
mp[i] = s;
q.push({i,s,k});
}
vector<int> v;
while(!q.empty()){
auto tmp = q.top();
q.pop();
int res = tmp.count;
if(res >= c){
sum ++;
ans[tmp.code] ++;
res -= c;
tmp.count = res;
if(res){
q.push(tmp);
}
}else{
int f = 0;
for(int j = 0;j < v.size();j ++){
if(res <= c - v[j]){
v[j] += res;
ans[tmp.code] ++;
f = 1;
break;
}
}
if(!f){
v.push_back(res);
ans[tmp.code] ++;
sum ++;
}
}
}
for(int i = 1;i <= n;i ++){
cout << mp[i] << " " << ans[i] << "\n";
}
cout << sum << "\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin >> t;
while(t --){
solve();
}
}
L2-047 锦标赛
有 2 k 2^k 2k 名选手将要参加一场锦标赛。锦标赛共有 k k k 轮,其中第 i i i 轮的比赛共有 2 k − i 2^{k−i} 2k−i场,每场比赛恰有两名选手参加并从中产生一名胜者。每场比赛的安排如下:
- 对于第 1 1 1 轮的第 j j j 场比赛,由第 ( 2 j − 1 ) (2j−1) (2j−1) 名选手对抗第 2 j 2j 2j 名选手。
- 对于第 i i i 轮的第 j 场比赛 ( i > 1 ) (i>1) (i>1),由第 ( i − 1 ) (i−1) (i−1) 轮第 ( 2 j − 1 ) (2j−1) (2j−1) 场比赛的胜者对抗第 ( i − 1 ) (i−1) (i−1) 轮第 2 j 2j 2j 场比赛的胜者。
第
k
k
k 轮唯一一场比赛的胜者就是整个锦标赛的最终胜者。
举个例子,假如共有
8
8
8 名选手参加锦标赛,则比赛的安排如下:
- 第 1 1 1 轮共 4 4 4 场比赛:选手 1 1 1 vs 选手 2 2 2,选手 3 3 3 vs 选手 4 4 4,选手 5 5 5 vs 选手 6 6 6,选手 7 7 7 vs 选手 8 8 8。
- 第 2 2 2 轮共 2 2 2 场比赛:第 1 1 1 轮第 1 1 1 场的胜者 vs 第 1 1 1 轮第 2 2 2 场的胜者,第 1 1 1 轮第 3 3 3 场的胜者 vs 第 1 1 1 轮第 4 4 4 场的胜者。
- 第 3 3 3 轮共 1 1 1 场比赛:第 2 2 2 轮第 1 1 1 场的胜者 vs 第 2 2 2 轮第 2 2 2 场的胜者。
已知每一名选手都有一个能力值,其中第 i i i 名选手的能力值为 a [ i ] a[i] a[i] 。在一场比赛中,若两名选手的能力值不同,则能力值较大的选手一定会打败能力值较小的选手;若两名选手的能力值相同,则两名选手都有可能成为胜者。
解题思路
这题分没拿满,直接按照题意大致模拟了一下,可以直接看下代码先,到时候再改下。
参考代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using ld = long double;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
void solve(){
int k;
cin >> k;
vector<int> a((1 << k) + 1);
queue<int> q;
for(int i = 1;i <= (1 << (k - 1));i ++){
int x;
cin >> x;
a[i * 2] = x;
q.push(i * 2 - 1);
}
int f = 0;
for(int i = 2;i <= k;i ++){
for(int j = 1;j <= (1 << (k - i));j ++){
int x;
cin >> x;
int k1 = q.front() + 1;
q.pop();
int k2 = q.front() + 1;
q.pop();
if(x <= a[k1] && x <= a[k2]){
// cout << x << "\n";
// cout << a[k1] << " " << a[k2] << "\n";
f = 1;
continue;
}
if(x >= a[k1] && x >= a[k2]){
if(a[k1] > a[k2]){
a[k1 - 1] = x;
q.push(k2 - 1);
}else{
a[k2 - 1] = x;
q.push(k1 - 1);
}
continue;
}
if(x >= a[k1]){
a[k1 - 1] = x;
q.push(k2 - 1);
continue;
}
if(x >= a[k2]){
a[k2 - 1] = x;
q.push(k1 - 1);
continue;
}
}
}
int w;
cin >> w;
if(f){
cout << "No Solution";
}else{
a[q.front()] = w;
for(int i = 1;i <= (1 << k);i ++){
if(i != 1){
cout << " ";
}
cout << a[i];
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin >> t;
while(t --){
solve();
}
}
L2-048 寻宝图
给定一幅地图,其中有水域,有陆地。被水域完全环绕的陆地是岛屿。有些岛屿上埋藏有宝藏,这些有宝藏的点也被标记出来了。本题就请你统计一下,给定的地图上一共有多少岛屿,其中有多少是有宝藏的岛屿。
解题思路
用bfs计算一下有多少个不为 0 0 0 的连通块就是岛屿的数量,然后再判断一下这个连通块中是否存在不等于 1 1 1 的点的就是宝藏的数量。
参考代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using ld = long double;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int dx[] = {-1,1,0,0};
int dy[] = {0,0,-1,1};
void solve(){
int n,m;
cin >> n >> m;
vector<string> s(n + 1);
for(int i = 1;i <= n;i ++){
cin >> s[i];
s[i] = '?' + s[i];
}
vector<vector<int>> vis(n + 1,vector<int>(m + 1));
int ans1 = 0,ans2 = 0;
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= m;j ++){
if(s[i][j] != '0' && !vis[i][j]){
ans1 ++;
queue<pair<int,int>> q;
q.push({i,j});
int f = 0;
vis[i][j] = 1;
while(!q.empty()){
auto [x,y] = q.front();
q.pop();
if(s[x][y] != '1'){
f = 1;
}
for(int k = 0;k < 4;k ++){
int kx = dx[k] + x,ky = dy[k] + y;
if(kx >= 1 && kx <= n && ky >= 1 && ky <= m && !vis[kx][ky]){
if(s[kx][ky] != '0'){
vis[kx][ky] = 1;
q.push({kx,ky});
}
}
}
}
if(f){
ans2 ++;
}
}
}
}
cout << ans1 << " " << ans2 << "\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin >> t;
while(t --){
solve();
}
}