2020年HZNU天梯训练赛 Round 2
2020年HZNU天梯训练赛 Round 2
时间:2020.7.15 27
完成情况:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
√ | √ | √ | √ | √ | √ | √ | √ | √ | ※ | |||||
✘ |
√ 当场做出来 ※做了一半来 ✘补题补出来
7-1 比较大小 (10分)
本题要求将输入的任意3个整数从小到大输出。
输入格式:
输入在一行中给出3个整数,其间以空格分隔。
输出格式:
在一行中将3个整数从小到大输出,其间以“->”相连。
输入样例:
4 2 8
输出样例:
2->4->8
简单到没东西可以给我逼逼赖赖了
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int main()
{
int a[3];
for(int i=0;i<3;i++)
cin>>a[i];
sort(a,a+3);
for(int i=0;i<2;i++)
cout<<a[i]<<"->";
cout<<a[2]<<endl;
return 0;
}
7-2 N个数求和 (20分)
本题的要求很简单,就是求N
个数字的和。麻烦的是,这些数字是以有理数分子/分母
的形式给出的,你输出的和也必须是有理数的形式。
输入格式:
输入第一行给出一个正整数N
(≤100)。随后一行按格式a1/b1 a2/b2 ...
给出N
个有理数。题目保证所有分子和分母都在长整型范围内。另外,负数的符号一定出现在分子前面。
输出格式:
输出上述数字和的最简形式 —— 即将结果写成整数部分 分数部分
,其中分数部分写成分子/分母
,要求分子小于分母,且它们没有公因子。如果结果的整数部分为0,则只输出分数部分。
输入样例1:
5
2/5 4/15 1/30 -2/60 8/3
输出样例1:
3 1/3
输入样例2:
2
4/3 2/3
输出样例2:
2
输入样例3:
3
1/3 -1/6 1/8
输出样例3:
7/24
借用gcd完成通分&约分
跟CC求直线差不太多
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;
LL gcd(LL a,LL b)
{
if(b==0)
return a;
return gcd(b,a%b);
}
int main()
{
LL i,j,n,a[101],b[101],x,y;
scanf("%lld",&n);
for(i=0;i<n;i++)
scanf("%lld/%lld",&a[i],&b[i]);
x=0,y=1;
for(i=0;i<n;i++)
{
LL x1= x*b[i]+y*a[i];LL y1= y* b[i];
x=x1/gcd(x1,y1);y=y1/gcd(x1,y1);
}
if(x==0){printf("0\n");}
else if(x%y==0){printf("%lld\n",x/y);}
else if(abs(x)<y&&x%y!=0){printf("%lld/%lld\n",x,y);}
else{printf("%lld %lld/%lld\n",x/y,x%y,y);}
return 0;
}
//(abs(x)>y)
7-3 A-B (20分)
本题要求你计算A−B。不过麻烦的是,A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串A−B。
输入格式:
输入在2行中先后给出字符串A和B。两字符串的长度都不超过104,并且保证每个字符串都是由可见的ASCII码和空白字符组成,最后以换行符结束。
输出格式:
在一行中打印出A−B的结果字符串。
输入样例:
I love GPLT! It's a fun game!
aeiou
输出样例:
I lv GPLT! It's fn gm!
这道题最大的痛点就是我PTA不允许gets()的存在😭
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int main()
{
int flag;
char a[10005],b[10005];
cin.getline(a,10005);
cin.getline(b,10005);
for(int i=0;i<strlen(a);i++)
{
flag=1;
for(int j=0;j<strlen(b);j++)
{
if(a[i]==b[j])
flag=0;
}
if(flag==1) cout<<a[i];
}
return 0;
}
7-4 计算指数 (5分)
真的没骗你,这道才是简单题 —— 对任意给定的不超过10的正整数n,要求你输出2n。不难吧?
输入格式:
输入在一行中给出一个不超过10的正整数n。
输出格式:
在一行中按照格式 2^n = 计算结果
输出2n的值。
输入样例:
5
输出样例:
2^5 = 32
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int main()
{
int n;
cin>>n;
cout<<"2^"<<n<<" = "<<pow(2,n);
return 0;
}
7-5 计算阶乘和 (10分)
对于给定的正整数N,需要你计算 S=1!+2!+3!+...+N!。
输入格式:
输入在一行中给出一个不超过10的正整数N。
输出格式:
在一行中输出S的值。
输入样例:
3
输出样例:
9
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int jc(int i)
{
int ans=1;
for(int j=1;j<=i;j++)
{
ans*=j;
}
return ans;
}
int main()
{
int n,sum=0;
cin>>n;
for(int i=1;i<=n;i++)
sum+=jc(i);
cout<<sum;
return 0;
}
7-6 简单题 (5分)
这次真的没骗你 —— 这道超级简单的题目没有任何输入。
你只需要在一行中输出事实:This is a simple problem.
就可以了。
This is a simple problem.
7-7 跟奥巴马一起画方块 (15分)
美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统。2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形。现在你也跟他一起画吧!
输入格式:
输入在一行中给出正方形边长N(3≤N≤21)和组成正方形边的某种字符C
,间隔一个空格。
输出格式:
输出由给定字符C
画出的正方形。但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们输出的行数实际上是列数的50%(四舍五入取整)。
输入样例:
10 a
输出样例:
aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int main()
{
int n;
char c;
scanf("%d %c",&n,&c);
if(n%2==0)
{
for(int i=0;i<n/2;i++)
{
for(int j=0;j<n;j++)
cout<<c;
cout<<endl;
}
}
else
{
for(int i=0;i<n/2+1;i++)
{
for(int j=0;j<n;j++)
cout<<c;
cout<<endl;
}
}
return 0;
}
7-8 查验身份证 (15分)
一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下:
首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};然后将计算的和对11取模得到值Z
;最后按照以下关系对应Z
值与校验码M
的值:
Z:0 1 2 3 4 5 6 7 8 9 10
M:1 0 X 9 8 7 6 5 4 3 2
现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码。
输入格式:
输入第一行给出正整数N(≤100)是输入的身份证号码的个数。随后N行,每行给出1个18位身份证号码。
输出格式:
按照输入的顺序每行输出1个有问题的身份证号码。这里并不检验前17位是否合理,只检查前17位是否全为数字且最后1位校验码计算准确。如果所有号码都正常,则输出All passed
。
输入样例1:
4
320124198808240056
12010X198901011234
110108196711301866
37070419881216001X
输出样例1:
12010X198901011234
110108196711301866
37070419881216001X
输入样例2:
2
320124198808240056
110108196711301862
输出样例2:
All passed
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[17]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
char M[15]={'1','0','X','9','8','7','6','5','4','3','2'};
int main()
{
int t,flag=1;
cin>>t;
while(t--)
{
char f[18];
int sum=0,z;
cin>>f;
for(int i=0;i<17;i++)
sum+=a[i]*(f[i]-'0');
z=sum%11;
if(f[17]!=M[z])
{
flag=0;
cout<<f<<endl;
}
}
if(flag==1)cout<<"All passed"<<endl;
return 0;
}
7-9 集合相似度 (25分)
给定两个整数集合,它们的相似度定义为:N**c/N**t×100%。其中N**c是两个集合都有的不相等整数的个数,N**t是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。
输入格式:
输入第一行给出一个正整数N(≤50),是集合的个数。随后N行,每行对应一个集合。每个集合首先给出一个正整数M(≤104),是集合中元素的个数;然后跟M个[0,109]区间内的整数。
之后一行给出一个正整数K(≤2000),随后K行,每行对应一对需要计算相似度的集合的编号(集合从1到N编号)。数字间以空格分隔。
输出格式:
对每一对需要计算的集合,在一行中输出它们的相似度,为保留小数点后2位的百分比数字。
输入样例:
3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3
输出样例:
50.00%
33.33%
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;
set<int>s[52];
int main()
{
set<int>::iterator it;
int n,m,t,x,y,z;
double x1,x2,ans;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>m;
while(m--){cin>>x;s[i].insert(x);}
}
cin>>t;
while(t--)
{
x1=0,x2=0;
cin>>y>>z;
for(it=s[y].begin();it!=s[y].end();it++)
{
if(s[z].find(*it)!=s[z].end()) x1+=1;
else x2+=1;
}
ans=x1/(x2+s[z].size())*100;
printf("%.2lf%%\n",ans);
}
return 0;
}
7-10 树的遍历 (25分)
给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例:
4 1 6 3 5 7 2
7-11 家庭房产 (25分)
给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。
输入格式:
输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产:
编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积
其中编号
是每个人独有的一个4位数的编号;父
和母
分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1
);k
(0≤k
≤5)是该人的子女的个数;孩子i
是其子女的编号。
输出格式:
首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:
家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积
其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。
输入样例:
10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100
输出样例:
3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000
https://www.cnblogs.com/littleLittleTiger/p/10588106.html
并查集板子
int find(int x)
{
while(x!=pre[x]) //如果该结点的父结点不是它自身
x=pre[x]; //那么就继续找它的父结点的父结点
return x;
}
//查找函数:用于查找结点的父结点。
void Union(int x,int y)
{
int fx=find(x); //找到x的根结点
int fy=find(y); //找到y的根结点
if(fx!=fy) //如果x和y的根结点不相同(x和y不属于同一个联通分支)
pre[fx]=fy; //就把x的根结点的父结点改为y的根结点
}
//合并函数:用于将两个结点所在的连通分支合为一个。通过将其中一个连通分支的根结点的父结点改为另一个连通分支的根结点。pre[fx]=fy;也可以根据题意做变动,比如这题要求输出家庭成员的最小编号,那么就要把编号大的根结点并入编号小的一边,这样直接输出一个连通分支的根结点就是这个联通分支中编号最小的了。
7-12 最长对称子串 (25分)
对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?
,最长对称子串为s PAT&TAP s
,于是你应该输出11。
输入格式:
输入在一行中给出长度不超过1000的非空字符串。
输出格式:
在一行中输出最长对称子串的长度。
输入样例:
Is PAT&TAP symmetric?
输出样例:
11
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;
int main(){
char s[1005];
int ans=1,cnt,temp;
cin.getline(s,10005);
for(int i=0;i<strlen(s);i++)//正序
{
cnt=1,temp=i;
//cout>>k;
for(int j=strlen(s)-1;j>i;j--)//倒序
{
if(s[temp]==s[j])//
{
if(temp+1==j)//中间部分为T&T
{
if(ans<=cnt*2)ans=cnt*2;break;
}
if(temp==j)//中间部分为T&&T
{
if(ans<=cnt*2-1)ans=cnt*2-1;break;
}
if(s[temp+1]==s[j-1]){cnt++;temp++;}//不断靠近
else cnt=1;
}
}
}
cout<<ans<<endl;
return 0;
}
7-13 垃圾箱分布 (30分)
大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。
现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。
输入格式:
输入第一行给出4个正整数:N(≤103)是居民点的个数;M(≤10)是垃圾箱候选地点的个数;K(≤104)是居民点和垃圾箱候选地点之间的道路的条数;D**S是居民点与垃圾箱之间不能超过的最大距离。所有的居民点从1到N编号,所有的垃圾箱候选地点从G1到G**M编号。
随后K行,每行按下列格式描述一条道路:
P1 P2 Dist
其中P1
和P2
是道路两端点的编号,端点可以是居民点,也可以是垃圾箱候选点。Dist
是道路的长度,是一个正整数。
输出格式:
首先在第一行输出最佳候选地点的编号。然后在第二行输出该地点到所有居民点的最小距离和平均距离。数字间以空格分隔,保留小数点后1位。如果解不存在,则输出No Solution
。
输入样例1:
4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2
输出样例1:
G1
2.0 3.3
输入样例2:
2 1 2 10
1 G1 9
2 G1 20
输出样例2:
No Solution
题目要找最短路中的最大值,这里最短路是一个垃圾箱在到每个村庄的最短距离中取最小值 。 然后还要取每个垃圾箱的最大值,如果最大值一样要去最取平均值。
打算等复习到dijkstra再回来补。
7-14 迎风一刀斩 (30分)
迎着一面矩形的大旗一刀斩下,如果你的刀够快的话,这笔直一刀可以切出两块多边形的残片。反过来说,如果有人拿着两块残片来吹牛,说这是自己迎风一刀斩落的,你能检查一下这是不是真的吗?
注意摆在你面前的两个多边形可不一定是端端正正摆好的,它们可能被平移、被旋转(逆时针90度、180度、或270度),或者被(镜像)翻面。
这里假设原始大旗的四边都与坐标轴是平行的。
输入格式:
输入第一行给出一个正整数N(≤20),随后给出N对多边形。每个多边形按下列格式给出:
k**x1y1⋯xky**k
其中k(2<k≤10)是多边形顶点个数;(x**i,y**i)(0≤x**i,y**i≤108)是顶点坐标,按照顺时针或逆时针的顺序给出。
注意:题目保证没有多余顶点。即每个多边形的顶点都是不重复的,任意3个相邻顶点不共线。
输出格式:
对每一对多边形,输出YES
或者NO
。
输入样例:
8
3 0 0 1 0 1 1
3 0 0 1 1 0 1
3 0 0 1 0 1 1
3 0 0 1 1 0 2
4 0 4 1 4 1 0 0 0
4 4 0 4 1 0 1 0 0
3 0 0 1 1 0 1
4 2 3 1 4 1 7 2 7
5 10 10 10 12 12 12 14 11 14 10
3 28 35 29 35 29 37
3 7 9 8 11 8 9
5 87 26 92 26 92 23 90 22 87 22
5 0 0 2 0 1 1 1 2 0 2
4 0 0 1 1 2 1 2 0
4 0 0 0 1 1 1 2 0
4 0 0 0 1 1 1 2 0
输出样例:
YES
NO
YES
YES
YES
YES
NO
YES
https://blog.csdn.net/foreyes_1001/article/details/52209062
7-15 特殊堆栈 (30分)
堆栈是一种经典的后进先出的线性结构,相关的操作主要有“入栈”(在堆栈顶插入一个元素)和“出栈”(将栈顶元素返回并从堆栈中删除)。本题要求你实现另一个附加的操作:“取中值”——即返回所有堆栈中元素键值的中值。给定 N 个元素,如果 N 是偶数,则中值定义为第 N/2 小元;若是奇数,则为第 (N+1)/2 小元。
输入格式:
输入的第一行是正整数 N(≤105)。随后 N 行,每行给出一句指令,为以下 3 种之一:
Push key
Pop
PeekMedian
其中 key
是不超过 105 的正整数;Push
表示“入栈”;Pop
表示“出栈”;PeekMedian
表示“取中值”。
输出格式:
对每个 Push
操作,将 key
插入堆栈,无需输出;对每个 Pop
或 PeekMedian
操作,在一行中输出相应的返回值。若操作非法,则对应输出 Invalid
。
输入样例:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
输出样例:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid
写的时候用的笨办法,就不停的用sort 还用了两重循环完成插入。然后超时了。只过了第一个测试点(虽然狗到了15分,但是我debug整整de了一小时)。
然后看题解的时候发现有lower_bound这个好东西,下面先粘贴一下其具体能实现的功能。
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
总的思路没有大问题,将笨蛋sort变成insert插入,将笨蛋换位变成erase就可以避免超时了
👇这个是笨蛋代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;
int n,a[10005]={0},b[10005]={0},cnt=0;
char op[10];
int main()
{
cin>>n;
while(n--)
{
memset(op,'\0',sizeof(op));
cin>>op;
if(op[0]=='P'&&op[1]=='u')
{
cin>>a[cnt];
//sort(a,a+cnt);
b[cnt]=a[cnt];
cnt++; //这一句的位置微调了好多次
sort(b,b+cnt); //这个cnt加加减减的真的搞吐了
/*for(int i=0;i<cnt;++i)
cout<<b[i]<<"***";
cout<<endl;*/
}
if(op[0]=='P'&&op[1]=='o')//这里我怕后面的长度或者结尾存在0,对是否相等的判断有影响就只用了前两位
{
if(cnt<=0){cout<<"Invalid"<<endl;}
else
{ cout<<a[cnt-1]<<endl;
for(int i=0;i<cnt;++i)
{
if(b[i]==a[cnt-1])
{
for(int j=i;j<cnt-1;j++)
b[j]=b[j+1];
}
}
a[cnt-1]=0;cnt--;
}
}
if(op[0]=='P'&&op[1]=='e')
{
if(cnt<=0){cout<<"Invalid"<<endl;}
else if((cnt)%2==0)cout<<b[(cnt-1)/2]<<endl;
else cout<<b[(cnt-1+1)/2]<<endl;
}
}
return 0;
}
然后下面是更改后的代码 和一些知识点
vector迭代器( vector
::iterator it = vect.begin(); ) 除了使用下标来访问vector对象的元素外,标准库还提供了另一种检测元素的方法:使用迭代器(iterator),它是一种允许程序员检查容器内元素,并实现元素遍历的数据类型。
标准库为每一种标准容器(包括vector)定义了一种迭代器类型。迭代器类型提供了比下标操作更一般化的方法:所有的标准库容器都定义了相应的迭代器类型,而只有少数的容器支持下标操作。因为迭代器对所有的容器都适用,现代C++程序更倾向于使用迭代器而不是下标操作访问容器元素,即使对支持下标操作的vector类型也这样。
vector的各种说明、操作:
https://blog.csdn.net/weixin_41743247/article/details/90635931
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long LL;
int main()
{
int n;
vector<int> a,b;
cin>>n;
vector<int>::iterator it;//迭代器
while(n--)
{
string s;
cin>>s; //用string读入就不用怕长度
if(s=="Push")
{
int x;
cin>>x;
a.push_back(x); //在a的第一个元素(从第0个算起)位置插入数值
it=lower_bound(b.begin(),b.end(),x);
b.insert(it,x);
}
if(s=="Pop")
{
if(a.size()==0)cout<<"Invalid"<<endl;
else
{
it=lower_bound(b.begin(),b.end(),a[a.size()-1]);
b.erase(it);//删除b中的位置是it的元素
//a.erase(a.begin()+1,a.begin()+3);删除a中第一个(从第0个算起)到第二个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)结束
cout<<a[a.size()-1]<<endl;
a.pop_back();//删除a向量的最后一个元素
}
}
if(s=="PeekMedian")
{
if(a.size()==0)cout<<"Invalid"<<endl;
else
{
if(a.size()%2==0)cout<<b[b.size()/2-1]<<endl;
else cout<<b[b.size()/2]<<endl;
}
}
}
return 0;
}