2022团体程序设计天梯赛初体验个人题解
一、L1-L2题目
L1-1 今天我要赢 (5 分)
2018 年我们曾经出过一题,是输出“2018 我们要赢”。今年是 2022 年,你要输出的句子变成了“我要赢!就在今天!”然后以比赛当天的日期落款。
输入格式:
本题没有输入。
输出格式:
输出分 2 行。在第一行中输出 I’m gonna win! Today!,在第二行中用 年年年年-月月-日日 的格式输出比赛当天的日期。已知比赛的前一天是 2022-04-22。
输入样例:
无
输出样例(第二行的内容要你自己想一想,这里不给出):
I’m gonna win! Today!
这一行的内容我不告诉你…… 你要自己输出正确的日期呀~
- 直接打印
#include<iostream>
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
typedef pair<int,int> pii;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout<<"I'm gonna win! Today!"<<endl<<"2022-04-23"<<endl;
return 0;
}
L1-2 种钻石 (5 分)
2019年10月29日,中央电视台专题报道,中国科学院在培育钻石领域,取得科技突破。科学家们用金刚石的籽晶片作为种子,利用甲烷气体在能量作用下形成碳的等离子体,慢慢地沉积到钻石种子上,一周“种”出了一颗 1 克拉大小的钻石。
本题给出钻石的需求量和人工培育钻石的速度,请你计算出货需要的时间。
输入格式:
输入在一行中给出钻石的需求量 N(不超过 107 的正整数,以微克拉为单位)和人工培育钻石的速度 v(1≤v≤200,以微克拉/天为单位的整数)。
输出格式:
在一行中输出培育 N 微克拉钻石需要的整数天数。不到一天的时间不算在内。
输入样例:
102000 130
输出样例:
784
- 相除就行 向下取整
#include<iostream>
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
typedef pair<int,int> pii;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int n,v;
cin>>n>>v;
cout<<n/v;
return 0;
}
L1-3 谁能进图书馆 (10 分)
为了保障安静的阅读环境,有些公共图书馆对儿童入馆做出了限制。例如“12 岁以下儿童禁止入馆,除非有 18 岁以上(包括 18 岁)的成人陪同”。现在有两位小/大朋友跑来问你,他们能不能进去?请你写个程序自动给他们一个回复。
输入格式:
输入在一行中给出 4 个整数:
禁入年龄线 陪同年龄线 询问者1的年龄 询问者2的年龄
这里的 禁入年龄线是指严格小于该年龄的儿童禁止入馆; 陪同年龄线是指大于等于该年龄的人士可以陪同儿童入馆。默认两个询问者的编号依次分别为 1 和 2;年龄和年龄线都是 [1, 200] 区间内的整数,并且保证 陪同年龄线 严格大于 禁入年龄线。
输出格式:
在一行中输出对两位询问者的回答,如果可以进就输出 年龄-Y,否则输出 年龄-N,中间空 1 格,行首尾不得有多余空格。
在第二行根据两个询问者的情况输出一句话:
- 如果两个人必须一起进,则输出 qing X zhao gu hao Y,其中 X 是陪同人的编号, Y 是小孩子的编号;
- 如果两个人都可以进但不是必须一起的,则输出 huan ying ru guan;
- 如果两个人都进不去,则输出 zhang da zai lai ba;
- 如果一个人能进一个不能,则输出 X: huan ying ru guan,其中 X 是可以入馆的那个人的编号。
输入样例 1:
12 18 18 8
输出样例 1:
18-Y 8-Y
qing 1 zhao gu hao 2
输入样例 2:
12 18 10 15
输出样例 2:
10-N 15-Y
2: huan ying ru guan
- 只不过有些繁琐,写清楚就行,注意输出拼音别敲错
#include<iostream>
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
typedef pair<int,int> pii;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int a,b,c,d;
cin>>a>>b>>c>>d;
if(c<a){
if(d<a){
cout<<c<<"-N "<<d<<"-N"<<endl;
cout<<"zhang da zai lai ba"<<endl;
}
else if(d>=b){
cout<<c<<"-Y "<<d<<"-Y"<<endl;
cout<<"qing 2 zhao gu hao 1"<<endl;
}
else{
cout<<c<<"-N "<<d<<"-Y"<<endl;
cout<<"2: huan ying ru guan"<<endl;
}
}
else if(c>=b){
cout<<c<<"-Y "<<d<<"-Y"<<endl;
if(d<a)
cout<<"qing 1 zhao gu hao 2"<<endl;
else
cout<<"huan ying ru guan"<<endl;
}
else{
if(d<a){
cout<<c<<"-Y "<<d<<"-N"<<endl;
cout<<"1: huan ying ru guan"<<endl;
}
else{
cout<<c<<"-Y "<<d<<"-Y"<<endl;
cout<<"huan ying ru guan"<<endl;
}
}
return 0;
}
L1-4 拯救外星人 (10 分)
你的外星人朋友不认得地球上的加减乘除符号,但是会算阶乘 —— 正整数 N 的阶乘记为 “N!”,是从 1 到 N 的连乘积。所以当他不知道“5+7”等于多少时,如果你告诉他等于“12!”,他就写出了“479001600”这个答案。
本题就请你写程序模仿外星人的行为。
输入格式:
输入在一行中给出两个正整数 A 和 B。
输出格式:
在一行中输出 (A+B) 的阶乘。题目保证 (A+B) 的值小于 12。
输入样例:
3 6
输出样例:
362880
- 求阶层,数据太弱 long long 甚至都不需要
#include<iostream>
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
typedef pair<int,int> pii;
int fun(int a){
if(a==1) return 1;
else return a*fun(a-1);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int A,B;
cin>>A>>B;
cout<<fun(A+B)<<endl;
return 0;
}
L1-5 试试手气 (15 分)
我们知道一个骰子有 6 个面,分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状态,即它们朝上一面的点数,让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙,每次摇出的结果都满足以下两个条件:
- 每个骰子摇出的点数都跟它之前任何一次出现的点数不同;
- 在满足条件 1 的前提下,每次都能让每个骰子得到可能得到的最大点数。
那么你应该可以预知自己第 n 次(1≤n≤5)摇出的结果。
输入格式:
输入第一行给出 6 个骰子的初始点数,即 [1,6] 之间的整数,数字间以空格分隔;第二行给出摇的次数 n(1≤n≤5)。
输出格式:
在一行中顺序列出第 n 次摇出的每个骰子的点数。数字间必须以 1 个空格分隔,行首位不得有多余空格。
输入样例:
3 6 5 4 1 4
3
输出样例:
4 3 3 3 4 3
样例解释:
这 3 次摇出的结果依次为:
6 5 6 6 6 6
5 4 4 5 5 5
4 3 3 3 4 3
- 我是创建一个6*6数组模拟每次选择就置为1
#include<iostream>
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
typedef pair<int,int> pii;
int a[10][10],ans[10];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
for(int i=1;i<=6;++i){
int x;
cin>>x;
a[i][x]=1;
}
int n;
cin>>n;
while(n--){
for(int i=1;i<=6;++i){
for(int j=6;j>=1;--j){
if(!a[i][j]){
a[i][j]=1;
ans[i]=j;
break;
}
}
}
}
cout<<ans[1];
for(int i=2;i<=6;++i){
cout<<" "<<ans[i];
}
cout<<endl;
return 0;
}
L1-6 斯德哥尔摩火车上的题 (15 分)
上图是新浪微博上的一则趣闻,是瑞典斯德哥尔摩火车上的一道题,看上去是段伪代码:
s = ''
a = '1112031584'
for (i = 1; i < length(a); i++) {
if (a[i] % 2 == a[i-1] % 2) {
s += max(a[i], a[i-1])
}
}
goto_url('www.multisoft.se/' + s)
其中字符串的 + 操作是连接两个字符串的意思。所以这道题其实是让大家访问网站 www.multisoft.se/112358(注意:比赛中千万不要访问这个网址!!!)。
当然,能通过上述算法得到 112358 的原始字符串 a 是不唯一的。本题就请你判断,两个给定的原始字符串,能否通过上述算法得到相同的输出?
输入格式:
输入为两行仅由数字组成的非空字符串,长度均不超过 104,以回车结束。
输出格式:
对两个字符串分别采用上述斯德哥尔摩火车上的算法进行处理。如果两个结果是一样的,则在一行中输出那个结果;否则分别输出各自对应的处理结果,每个占一行。题目保证输出结果不为空。
输入样例 1:
1112031584
011102315849
输出样例 1:
112358
输入样例 2:
111203158412334
12341112031584
输出样例 2:
1123583
112358
- 读懂题意没有难度
#include<iostream>
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
typedef pair<int,int> pii;
string fun(string a){
string s1="";
for(int i=1;i<a.length();i++)
{
if(a[i]%2==a[i-1]%2){
s1 += max(a[i], a[i-1]);
}
}
return s1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
string a,b,s1,s2;
cin>>a>>b;
s1=fun(a);
s2=fun(b);
if(s1==s2) cout<<s1;
else cout<<s1<<endl<<s2;
return 0;
}
L1-7 机工士姆斯塔迪奥 (20 分)
在 MMORPG《最终幻想14》的副本“乐欲之所瓯博讷修道院”里,BOSS 机工士姆斯塔迪奥将会接受玩家的挑战。
你需要处理这个副本其中的一个机制:N×M 大小的地图被拆分为了 N×M 个 1×1 的格子,BOSS 会选择若干行或/及若干列释放技能,玩家不能站在释放技能的方格上,否则就会被击中而失败。
给定 BOSS 所有释放技能的行或列信息,请你计算出最后有多少个格子是安全的。
输入格式:
输入第一行是三个整数 N,M,Q (1≤N×M≤105,0≤Q≤1000),表示地图为 N 行 M 列大小以及选择的行/列数量。
接下来 Q 行,每行两个数 Ti,Ci,其中 Ti=0 表示 BOSS 选择的是一整行,Ti=1 表示选择的是一整列,Ci 为选择的行号/列号。行和列的编号均从 1 开始。
输出格式:
输出一个数,表示安全格子的数量。
输入样例:
5 5 3
0 2
0 4
1 3
输出样例:
12
- 用两个set分别去存放行和列,结果就是nm - 行的长度 * m-列的长度 * n+重复的(行长度列长度)
#include<iostream>
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
typedef pair<int,int> pii;
set<int> s1,s2;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int n,m,q;
cin>>n>>m>>q;
while(q--){
int x,y;
cin>>x>>y;
if(!x){
s1.insert(y);
}else{
s2.insert(y);
}
}
cout<<n*m-s1.size()*m-s2.size()*n+s1.size()*s2.size()<<endl;
return 0;
}
L1-8 静静的推荐 (20 分)
天梯赛结束后,某企业的人力资源部希望组委会能推荐一批优秀的学生,这个整理推荐名单的任务就由静静姐负责。企业接受推荐的
流程是这样的:
- 只考虑得分不低于 175 分的学生;
- 一共接受 K 批次的推荐名单;
- 同一批推荐名单上的学生的成绩原则上应严格递增;
- 如果有的学生天梯赛成绩虽然与前一个人相同,但其参加过 PAT 考试,且成绩达到了该企业的面试分数线,则也可以接受。
给定全体参赛学生的成绩和他们的 PAT 考试成绩,请你帮静静姐算一算,她最多能向企业推荐多少学生?
输入格式:
输入第一行给出 3 个正整数:N(≤105)为参赛学生人数,K(≤5×103)为企业接受的推荐批次,S(≤100)为该企业的 PAT 面试分数线。
随后 N 行,每行给出两个分数,依次为一位学生的天梯赛分数(最高分 290)和 PAT 分数(最高分 100)。
输出格式:
在一行中输出静静姐最多能向企业推荐的学生人数。
输入样例:
10 2 90
203 0
169 91
175 88
175 0
175 90
189 0
189 0
189 95
189 89
256 100
输出样例:
8
样例解释:
第一批可以选择 175、189、203、256 这四个分数的学生各一名,此外 175 分 PAT 分数达到 90 分的学生和 189 分 PAT 分数达到 95 分的学生可以额外进入名单。第二批就只剩下 175、189 两个分数的学生各一名可以进入名单了。最终一共 8 人进入推荐名单。
- 看懂题意就比较好做 ,这里我先将额外进入的人数统计ans++,然后 用map去查找分数对应的人数, 如果人数小于批次那么就加上实际人数,如果人数大于批数 那么就加上批次S即可
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
typedef pair<int,int> pii;
pii a[100005];
int ans;
vector<int > ve;
map<int,int> mp;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int n,k,sta;
cin>>n>>k>>sta;
for(int i=0;i<n;++i){
cin>>a[i].first>>a[i].second;
}
sort(a,a+n);
for(int i=0;i<n;++i){
if(a[i].first>=175&&a[i].second>=sta){
ans++;
}
if(a[i].first>=175&&a[i].second<sta){
mp[a[i].first]++;
}
}
for(auto i:mp){
if(i.second<=k) {
ans+=i.second;
}else{
ans+=k;
}
}
cout<<ans<<endl;
return 0;
}
L2-1 插松枝 (25 分)
人造松枝加工场的工人需要将各种尺寸的塑料松针插到松枝干上,做成大大小小的松枝。他们的工作流程(并不)是这样的:
每人手边有一只小盒子,初始状态为空。
每人面前有用不完的松枝干和一个推送器,每次推送一片随机型号的松针片。
工人首先捡起一根空的松枝干,从小盒子里摸出最上面的一片松针 —— 如果小盒子是空的,就从推送器上取一片松针。将这片松针插到枝干的最下面。
工人在插后面的松针时,需要保证,每一步插到一根非空松枝干上的松针片,不能比前一步插上的松针片大。如果小盒子中最上面的松针满足要求,就取之插好;否则去推送器上取一片。如果推送器上拿到的仍然不满足要求,就把拿到的这片堆放到小盒子里,继续去推送器上取下一片。注意这里假设小盒子里的松针片是按放入的顺序堆叠起来的,工人每次只能取出最上面(即最后放入)的一片。
当下列三种情况之一发生时,工人会结束手里的松枝制作,开始做下一个:
(1)小盒子已经满了,但推送器上取到的松针仍然不满足要求。此时将手中的松枝放到成品篮里,推送器上取到的松针压回推送器,开始下一根松枝的制作。
(2)小盒子中最上面的松针不满足要求,但推送器上已经没有松针了。此时将手中的松枝放到成品篮里,开始下一根松枝的制作。
(3)手中的松枝干上已经插满了松针,将之放到成品篮里,开始下一根松枝的制作。
现在给定推送器上顺序传过来的 N 片松针的大小,以及小盒子和松枝的容量,请你编写程序自动列出每根成品松枝的信息
输入格式:
输入在第一行中给出 3 个正整数:N(≤103),为推送器上松针片的数量;M(≤20)为小盒子能存放的松针片的最大数量;K(≤5)为一根松枝干上能插的松针片的最大数量。
随后一行给出 N 个不超过 100 的正整数,为推送器上顺序推出的松针片的大小。
输出格式:
每支松枝成品的信息占一行,顺序给出自底向上每片松针的大小。数字间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
8 3 4
20 25 15 18 20 18 8 5
输出样例:
20 15
20 18 18 8
25 5
- 我是用队列模拟推送器,栈模拟小盒子,vector[i]模拟第i个松枝干。设立flag=0就是从推送器上面取,flag=1是从小盒子里面取,模拟过程,设立出口,不满足就break到下一个vector中。可能写得比较复杂。
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
typedef pair<int,int> pii;
queue<int> qu;
stack<int> st;
vector<int> ve[10000];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int n,m,k,flag=0,ans1;
cin>>n>>m>>k;
while(n--){
int a;
cin>>a;
qu.push(a);
}
for(int i=0;i<10000;i++){
while(ve[i].size()!=k){
flag=0;
int now=qu.front();
if(st.size()>0){
now=st.top();
flag=1;
}
if(flag){
if(ve[i].size()==0||ve[i][ve[i].size()-1]>=now){
ve[i].push_back(now);
st.pop();
}
else{
if(qu.size()==0){
break;
}
else{
now=qu.front();
flag=0;
}
}
}
if(flag==0){
if(ve[i].size()==0||ve[i][ve[i].size()-1]>=now){
ve[i].push_back(now);
qu.pop();
}else{
if(st.size()<m){
st.push(now);
qu.pop();
}else{
break;
}
}
}
if(st.size()==0&&qu.size()==0){
ans1=i;
break;
}
}
if(st.size()==0&&qu.size()==0){
ans1=i;
break;
}
}
int x=0;
for(int i=0;i<=ans1;i++){
x=0;
for(auto j:ve[i]){
++x;
if(x==ve[i].size())
cout<<j<<endl;
else
cout<<j<<" ";
}
}
return 0;
}
L2-2 老板的作息表 (25 分)
本题就请你编写程序,检查任意一张时间表,找出其中没写出来的时间段。
输入格式:
输入第一行给出一个正整数 N,为作息表上列出的时间段的个数。随后 N 行,每行给出一个时间段,格式为:
hh:mm:ss - hh:mm:ss
其中 hh、mm、ss 分别是两位数表示的小时、分钟、秒。第一个时间是开始时间,第二个是结束时间。题目保证所有时间都在一天之内(即从 00:00:00 到 23:59:59);每个区间间隔至少 1 秒;并且任意两个给出的时间区间最多只在一个端点有重合,没有区间重叠的情况。
输出格式:
按照时间顺序列出时间表中没有出现的区间,每个区间占一行,格式与输入相同。题目保证至少存在一个区间需要输出。
输入样例:
8
13:00:00 - 18:00:00
00:00:00 - 01:00:05
08:00:00 - 09:00:00
07:10:59 - 08:00:00
01:00:05 - 04:30:00
06:30:00 - 07:10:58
05:30:00 - 06:30:00
18:00:00 - 19:00:00
输出样例:
04:30:00 - 05:30:00
07:10:58 - 07:10:59
09:00:00 - 13:00:00
19:00:00 - 23:59:59
- l2中最简单一题,没有难度就结构体排个序就出来了,最后wa掉一组结果,发现原来当n=1时不能输出,单独写出即可AC。
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
typedef pair<int,int> pii;
struct node{
string a,b;
};
bool cmp(node aa,node bb){
return aa.a<bb.a;
}
bool check(node aa,node bb){
if(aa.b==bb.a)
return 0;
else
return 1;
}
node no[100000];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
cin.ignore();
for(int i=0;i<n;++i){
string s;
getline(cin,s);
no[i].a=s.substr(0,8);
no[i].b=s.substr(11,8);
}
sort(no,no+n,cmp);
if(n==1){
if(no[0].a!="00:00:00")
cout<<"00:00:00 - "<<no[0].a<<endl;
if(no[0].b!="23:59:59")
cout<<no[0].b<<" - 23:59:59"<<endl;
}
for(int i=0;i<n-1;++i){
if(i==0&&no[i].a!="00:00:00")
cout<<"00:00:00 - "<<no[i].a<<endl;
if(check(no[i],no[i+1]))
cout<<no[i].b<<" - "<<no[i+1].a<<endl;
if(i==n-2&&no[i+1].b!="23:59:59")
cout<<no[i+1].b<<" - 23:59:59"<<endl;
}
return 0;
}
L2-3 龙龙送外卖 (25 分)
龙龙是“饱了呀”外卖软件的注册骑手,负责送帕特小区的外卖。帕特小区的构造非常特别,都是双向道路且没有构成环 —— 你可以简单地认为小区的路构成了一棵树,根结点是外卖站,树上的结点就是要送餐的地址。
每到中午 12 点,帕特小区就进入了点餐高峰。一开始,只有一两个地方点外卖,龙龙简单就送好了;但随着大数据的分析,龙龙被派了更多的单子,也就送得越来越累……
看着一大堆订单,龙龙想知道,从外卖站出发,访问所有点了外卖的地方至少一次(这样才能把外卖送到)所需的最短路程的距离到底是多少?每次新增一个点外卖的地址,他就想估算一遍整体工作量,这样他就可以搞明白新增一个地址给他带来了多少负担。
输入格式:
输入第一行是两个数 N 和 M (2≤N≤105, 1≤M≤105),分别对应树上节点的个数(包括外卖站),以及新增的送餐地址的个数。
接下来首先是一行 N 个数,第 i 个数表示第 i 个点的双亲节点的编号。节点编号从 1 到 N,外卖站的双亲编号定义为 −1。
接下来有 M 行,每行给出一个新增的送餐地点的编号 Xi。保证送餐地点中不会有外卖站,但地点有可能会重复。
为了方便计算,我们可以假设龙龙一开始一个地址的外卖都不用送,两个相邻的地点之间的路径长度统一设为 1,且从外卖站出发可以访问到所有地点。
注意:所有送餐地址可以按任意顺序访问,且完成送餐后无需返回外卖站。
输出格式:
对于每个新增的地点,在一行内输出题目需要求的最短路程的距离。
输入样例:
7 4
-1 1 1 1 2 2 3
5
6
2
4
输出样例:
2
4
4
6
- 乍一看应该是建树,求深度之类的 emm 还不会(比较菜)以后来补
L2-4 大众情人 (25 分)
人与人之间总有一点距离感。我们假定两个人之间的亲密程度跟他们之间的距离感成反比,并且距离感是单向的。例如小蓝对小红患了单相思,从小蓝的眼中看去,他和小红之间的距离为 1,只差一层窗户纸;但在小红的眼里,她和小蓝之间的距离为 108000,差了十万八千里…… 另外,我们进一步假定,距离感在认识的人之间是可传递的。例如小绿觉得自己跟小蓝之间的距离为 2,则即使小绿并不直接认识小红,我们也默认小绿早晚会认识小红,并且因为跟小蓝很亲近的关系,小绿会觉得自己跟小红之间的距离为 1+2=3。当然这带来一个问题,如果小绿本来也认识小红,或者他通过其他人也能认识小红,但通过不同渠道推导出来的距离感不一样,该怎么算呢?我们在这里做个简单定义,就将小绿对小红的距离感定义为所有推导出来的距离感的最小值。
一个人的异性缘不是由最喜欢他/她的那个异性决定的,而是由对他/她最无感的那个异性决定的。我们记一个人 i 在一个异性 j 眼中的距离感为 Dij;将 i 的“异性缘”定义为 1/maxj∈S(i){Dij},其中 S(i) 是相对于 i 的所有异性的集合。那么“大众情人”就是异性缘最好(值最大)的那个人。
本题就请你从给定的一批人与人之间的距离感中分别找出两个性别中的“大众情人”。
输入格式:
输入在第一行中给出一个正整数 N(≤500),为总人数。于是我们默认所有人从 1 到 N 编号。
随后 N 行,第 i 行描述了编号为 i 的人与其他人的关系,格式为:
性别 K 朋友1:距离1 朋友2:距离2 …… 朋友K:距离K
其中 性别 是这个人的性别,F 表示女性,M 表示男性;K(<N 的非负整数)为这个人直接认识的朋友数;随后给出的是这 K 个朋友的编号、以及这个人对该朋友的距离感。距离感是不超过 106 的正整数。
题目保证给出的关系中一定两种性别的人都有,不会出现重复给出的关系,并且每个人的朋友中都不包含自己。
输出格式:
第一行给出自身为女性的“大众情人”的编号,第二行给出自身为男性的“大众情人”的编号。如果存在并列,则按编号递增的顺序输出所有。数字间以一个空格分隔,行首尾不得有多余空格。
输入样例:
6
F 1 4:1
F 2 1:3 4:10
F 2 4:2 2:2
M 2 5:1 3:2
M 2 2:2 6:2
M 2 3:1 2:5
输出样例:
2 3
4
- 读清楚题后 发现应该是个floyd算法,最后我是用set去存放结果从小到大,F和Mf分别去求直接写出即可(我的代码比较水,人比较菜)
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
const int inf=0x3f3f3f3f;
typedef pair<int,int> pii;
int G[1005][1005];
int dist[1005][1005];
int p[1005][1005];
int n;
void floyd(){
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(i==j){
dist[i][j]=0;
p[i][j]=-1;
}else{
dist[i][j]=G[i][j];
if(dist[i][j]==inf){
p[i][j]=-1;
}else{
p[i][j]=i;
}
}
}
}
for(int k=1;k<=n;++k){
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(dist[i][j]>dist[i][k]+dist[k][j]){
dist[i][j]=dist[i][k]+dist[k][j];
p[i][j]=p[k][j];
}
}
}
}
}
char c[1005];
int ans[1005];
set<int> se1,se2;
int main(){
//ios::sync_with_stdio(0);
//cin.tie(0);
//cout.tie(0);
cin>>n;
memset(G,inf,sizeof(G));
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;++i){
int n2;
cin>>c[i];
cin>>n2;
while(n2--){
int x,tmp;
scanf("%d:%d",&x,&tmp);
G[i][x]=tmp;
}
}
floyd();
for(int i=1;i<=n;++i){
if(c[i]=='F'){
for(int j=1;j<=n;++j){
if(c[j]=='M'&&i!=j){
ans[i]=max(ans[i],dist[j][i]);
}
}
}
if(c[i]=='M'){
for(int j=1;j<=n;++j){
if(c[j]=='F'&&i!=j){
ans[i]=max(ans[i],dist[j][i]);
}
}
}
}
int now1=inf,now2=inf;
for(int i=1;i<=n;++i){
if(c[i]=='F'){
if(ans[i]<now1){
now1=ans[i];
se1.clear();
se1.insert(i);
}
else if(ans[i]==now1){
se1.insert(i);
}
}
if(c[i]=='M'){
if(ans[i]<now2){
now2=ans[i];
se2.clear();
se2.insert(i);
}
else if(ans[i]==now2){
se2.insert(i);
}
}
}
int flag=0;
cout<<*se1.begin();
for(auto i:se1){
if(flag==1)
cout<<" "<<i;
flag=1;
}
cout<<endl<<*se2.begin();
flag=0;
for(auto i:se2){
if(flag==1)
cout<<" "<<i;
flag=1;
}
cout<<endl;
return 0;
}
L3-1 千手观音 (30 分)
人类喜欢用 10 进制,大概是因为人类有一双手 10 根手指用于计数。于是在千手观音的世界里,数字都是 10 000 进制的,因为每位观音有 1 000 双手 ……
千手观音们的每一根手指都对应一个符号(但是观音世界里的符号太难画了,我们暂且用小写英文字母串来代表),就好像人类用自己的 10 根手指对应 0 到 9 这 10 个数字。同样的,就像人类把这 10 个数字排列起来表示更大的数字一样,ta们也把这些名字排列起来表示更大的数字,并且也遵循左边高位右边低位的规则,相邻名字间用一个点 . 分隔,例如 pat.pta.cn 表示千手观音世界里的一个 3 位数。
人类不知道这些符号代表的数字的大小。不过幸运的是,人类发现了千手观音们留下的一串数字,并且有理由相信,这串数字是从小到大有序的!于是你的任务来了:请你根据这串有序的数字,推导出千手观音每只手代表的符号的相对顺序。
注意:有可能无法根据这串数字得到全部的顺序,你只要尽量推出能得到的结果就好了。当若干根手指之间的相对顺序无法确定时,就暂且按它们的英文字典序升序排列。例如给定下面几个数字:
pat
cn
lao.cn
lao.oms
pta.lao
pta.pat
cn.pat
我们首先可以根据前两个数字推断 pat < cn;根据左边高位的顺序可以推断 lao < pta < cn;再根据高位相等时低位的顺序,可以推断出 cn < oms,lao < pat。综上我们得到两种可能的顺序:lao < pat < pta < cn < oms;或者 lao < pta < pat < cn < oms,即 pat 和 pta 之间的相对顺序无法确定,这时我们按字典序排列,得到 lao < pat < pta < cn < oms。
输入格式:
输入第一行给出一个正整数 N (≤105),为千手观音留下的数字的个数。随后 N 行,每行给出一个千手观音留下的数字,不超过 10 位数,每一位的符号用不超过 3 个小写英文字母表示,相邻两符号之间用 . 分隔。
我们假设给出的数字顺序在千手观音的世界里是严格递增的。题目保证数字是 104 进制的,即符号的种类肯定不超过 104 种。
输出格式:
在一行中按大小递增序输出符号。当若干根手指之间的相对顺序无法确定时,按它们的英文字典序升序排列。符号间仍然用 . 分隔。
输入样例:
7
pat
cn
lao.cn
lao.oms
pta.lao
pta.pat
cn.pat
输出样例:
lao.pat.pta.cn.oms
- 乍一看拓扑排序之类的吧,l3的题太难了 做了队伍也不计分 不写了
二、赛后总结
L1的题花费过长时间大概1个小时十几分钟(太菜了),L2-1模拟太长时间估计花了40分钟(太菜了),L2-2和L2-4写出来应该没有问题,如果有时间回头去暴力一下L2-3,感觉应该没那多时间。不是专业的 L3放弃。。
可惜的是由于学校其他人原因,我们学校没有成绩,不说个人国三,至少团队是可以有省奖的,确实是有些遗憾的。关于题目其实天梯赛大部分难题都是数据结构的,算法方面很少,这学期正在学数据结构,还没完全掌握,说不定学完数据结构再回头来看有新的体会,到时候再补吧。