2020.10.10--pta阶梯赛练习2补题
7-3.N个数求和
本题的要求很简单,就是求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()函数求出最大公约数进而化简分数;
要注意不要出现除以0 的情况,不然就会浮点错误
#include<bits/stdc++.h> using namespace std; long long gcd(long long a,long long b) { long long t; if(a==0)return 0; else { while(b) { t=a%b; a=b; b=t; } return a; } } int main() { long long n,x=0,y=1,a[110],b[110],h; char ch; scanf("%lld",&n); scanf("%lld/%lld",&a[0],&b[0]); h=gcd(a[0],b[0]); x=a[0]; y=b[0]; if(x!=0)//** { x=x/h; y=y/h; } long long k,q; for(long long i=1;i<n;i++) { scanf("%lld/%lld",&a[i],&b[i]); k=y/gcd(y,b[i])*b[i];//求合并后的分母 x=x*k/y+a[i]*k/b[i];//求合并后的分子 y=k; h=gcd(x,y); if(h)//避免浮点错误 { x/=h; y/=h; } } //分情况讨论 if(x!=0&&x/y==0) { printf("%lld/%lld\n",x%y,y); } else if(x%y==0) { printf("%lld\n",x/y); } else { printf("%lld %lld/%lld\n",x/y,x%y,y); } }
7-9 名人堂与代金券
对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,总评成绩必须达到 60 分及以上,并且有另加福利:总评分在 [G, 100] 区间内者,可以得到 50 元 PAT 代金券;在 [60, G) 区间内者,可以得到 20 元PAT代金券。全国考点通用,一年有效。同时任课老师还会把总评成绩前 K 名的学生列入课程“名人堂”。本题就请你编写程序,帮助老师列出名人堂的学生,并统计一共发出了面值多少元的 PAT 代金券。
输入格式:
输入在第一行给出 3 个整数,分别是 N(不超过 10 000 的正整数,为学生总数)、G(在 (60,100) 区间内的整数,为题面中描述的代金券等级分界线)、K(不超过 100 且不超过 N 的正整数,为进入名人堂的最低名次)。接下来 N 行,每行给出一位学生的账号(长度不超过15位、不带空格的字符串)和总评成绩(区间 [0, 100] 内的整数),其间以空格分隔。题目保证没有重复的账号。
输出格式:
首先在一行中输出发出的 PAT 代金券的总面值。然后按总评成绩非升序输出进入名人堂的学生的名次、账号和成绩,其间以 1 个空格分隔。需要注意的是:成绩相同的学生享有并列的排名,排名并列时,按账号的字母序升序输出。
输入样例:
10 80 5
cy@zju.edu.cn 78
cy@pat-edu.com 87
1001@qq.com 65
uh-oh@163.com 96
test@126.com 39
anyone@qq.com 87
zoe@mit.edu 80
jack@ucla.edu 88
bob@cmu.edu 80
ken@163.com 70
输出样例:
360
1 uh-oh@163.com 96
2 jack@ucla.edu 88
3 anyone@qq.com 87
3 cy@pat-edu.com 87
5 bob@cmu.edu 80
5 zoe@mit.edu 80
题解:根据题意进行排序,但要注意序号的输出,用结构体输入每人的账号和成绩,再用判断函数进行从大到小和从小到大的排序,节约时间
#include<bits/stdc++.h> using namespace std; struct Student { string s; int score; }str[10010]; bool cmp(Student a,Student b) { if(a.score==b.score)return a.s<b.s; else return a.score>b.score; } int main() { int n,g,k,i,j; // string s[10010]; int ct=0; cin>>n>>g>>k; for(i=0;i<n;i++) { cin>>str[i].s; getchar(); cin>>str[i].score; if(str[i].score>=g&&str[i].score<=100)ct+=50; else if(str[i].score>=60&&str[i].score<g)ct+=20; } int m=0; sort(str,str+n,cmp); /*for(i=0;i<n;i++) { for(j=i+1;j<n;j++) { if(str[i].score<str[j].score) { t[i]=str[i]; str[i]=str[j]; str[j]=t[i]; } else if(str[i].score==str[j].score) { if(str[i].s>str[j].s) { t[i]=str[i]; str[i]=str[j]; str[j]=t[i]; } } } }*/ cout<<ct<<endl; int r=0,q=0; for(i=0;i<n;i++) { if(q!=str[i].score&&i>=k)break; if(q!=str[i].score) { r=i+1; } cout<<r<<" "<<str[i].s<<" "<<str[i].score<<endl; q=str[i].score; } }
7-11 部落
在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。
输入格式:
输入在第一行给出一个正整数N(≤),是已知小圈子的个数。随后N行,每行按下列格式给出一个小圈子里的人:
K [ [ ⋯ [
其中K是小圈子里的人数,[(,)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过1。
之后一行给出一个非负整数Q(≤),是查询次数。随后Q行,每行给出一对被查询的人的编号。
输出格式:
首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出Y,否则输出N。
输入样例:
4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7
输出样例:
10 2 Y N
题解:(运用并查集)
用一个数组(例fa[])来存储每个元素的父节点,现将他们的父节点设为他们自身,然后将同一个圈子的元素的父节点设为其中的同一个元素,就是该圈子元素的父节点相同
然后再查询两个元素的父节点是否一样,一样则输出“Y”,否则输出“N”;另设一个数组,初始化为0,将下标为编号的赋值为1,用于计算社区总人数,然后再遍历总人数,利用父节点等于自身下标来计算部落个数
#include<bits/stdc++.h> using namespace std; int fa[10100],rank[10100]={0}; //memset(rank,0,sizeof rank); /*inline void init(int k,int n) { fa[n]=k; rank[k]++; }*/ int find (int x)//查找父节点 { return x==fa[x]?x:(fa[x]=find(fa[x])); } inline void marge(int i,int j)//合并为相同的父节点 { int x=find(i),y=find(j); if(x!=y) { fa[x]=y; } // else fa[y]=x; //if(rank[x]==rank[y]&&x!=y)rank[y]++; } int main() { int n; cin>>n; int ct=0; for(int i=0;i<10001;i++)fa[i]=i;//初始化,将每个数的父结点初始化为自身 int k,b[10100]={0}; while(n--) { cin>>k; int s[k+5]; cin>>s[0]; b[s[0]]=1; for(int i=1;i<k;i++) { cin>>s[i]; // init(k,s[i]); b[s[i]]=1;//记录数组,用于计算社区总人数 marge(s[i],s[i-1]); } } for(int i=0;i<10001;i++) { if(b[i]==1)ct++; } cout<<ct<<" "; int j=0; for(int i=1;i<=ct;i++) { if(fa[i]==i)j++;//如果下标和数不一样则是不同的部落 } cout<<j<<endl; int q; cin>>q; while(q--) { int x,y; cin>>x>>y; // marge(x,y); printf("%s\n",find(x)==find(y)?"Y":"N"); } }
7-10.链表去重
给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。
输入格式:
输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。
随后 N 行,每行按以下格式描述一个结点:
地址 键值 下一个结点
其中地址是该结点的地址,键值是绝对值不超过1的整数,下一个结点是下个结点的地址。
输出格式:
首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。
输入样例:
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
输出样例:
00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1
题解:与天梯赛练习一里7-11重排链表一个做法,将链表重排,再用一个数组将排好的地址依次存储下来,再根据键值的绝对值将链表分为两部分
#include<bits/stdc++.h> #include<vector> using namespace std; const int N=100000; struct Node { int ad;//地址 int data;//键值 int next;//下个节点地址 }s[N]; int main() { vector<Node>b; int i,f,n,j=0,x,y,z; cin>>f>>n; for(i=0;i<n;i++) { cin>>x>>y>>z; s[x].ad=x; s[x].data=y; s[x].next=z; } int w[N]={0},q[N]={0},t[N]={0}; int c[N]={0},cnt=0; while(f!=-1) { c[cnt++]=f;//存储地址 b.push_back(s[f]);//链表按地址依次排序存储到b中 f=s[f].next; } int m=b.size(); cout<<m<<endl; int k=0,p=0; for(i=0;i<m;i++) { if(w[abs(b[i].data)]==0) { w[abs(b[i].data)]=1;//标记绝对值重复的键值 q[k++]=c[i]; // cout<<" q[k]="<<q[k-1]<<" b[i].ad="<<b[i].data<<endl; } else { t[p++]=c[i]; // cout<<" t[p]="<<t[p-1]<<" b[i].ad="<<b[i].data<<endl; } } for(i=0;i<k;i++) { //cout<<b[i].data<<endl; cout << setw(5) << setfill('0') << q[i] << " " << s[q[i]].data<<" "; if(i!=k-1) cout << setw(5) << setfill('0') << q[i+1]<<endl; else cout << -1 <<endl; } //cout<<p<<" "<<t[1]<<" "<<s[t[1]].data<<endl; for(int j=0; j<p; j++){ //cout<<b[87654].data<<endl; cout << setw(5) << setfill('0') << t[j] << " " << s[t[j]].data<<" "; if(j!=p-1) cout << setw(5) << setfill('0') << t[j+1]<<endl; else cout << -1 <<endl; } }
7-1估值一亿的AI核心代码

以上图片来自新浪微博。
本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是:
- 无论用户说什么,首先把对方说的话在一行中原样打印出来;
- 消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
- 把原文中所有大写英文字母变成小写,除了
I; - 把原文中所有独立的
can you、could you对应地换成I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词; - 把原文中所有独立的
I和me换成you; - 把原文中所有的问号
?换成惊叹号!; - 在一行中输出替换后的句子作为 AI 的回答。
输入格式:
输入首先在第一行给出不超过 10 的正整数 N,随后 N 行,每行给出一句不超过 1000 个字符的、以回车结尾的用户的对话,对话为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。
输出格式:
按题面要求输出,每个 AI 的回答前要加上 AI: 和一个空格。
输入样例:
6
Hello ?
Good to chat with you
can you speak Chinese?
Really?
Could you show me 5
What Is this prime? I,don 't know
输出样例:
Hello ?
AI: hello!
Good to chat with you
AI: good to chat with you
can you speak Chinese?
AI: I can speak chinese!
Really?
AI: really!
Could you show me 5
AI: I could show you 5
What Is this prime? I,don 't know
AI: what Is this prime! you,don't know
#include<string> #include<iostream> #include<vector> #include<cstdio> using namespace std; int main() { int n,i; cin>>n; getchar(); string s; vector<string>b;//每个元素都是字符串类型数组; while(n--) { //cout<<n<<endl; getline(cin,s); cout<<s<<endl<<"AI: "; //cout<<"AI: "; //cout<<m<<endl; for(i=0;i<s.size();i++) { if(s[i]>='A'&&s[i]<='Z') { if(s[i]!='I')s[i]+=32; } else if((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z'))continue; else if(s[i]!=' ')//排除字母和数字后当为标点符号时 { s.insert(i," ");//在标点符号前插入空格,便于找出独立性的单词 i++; } if(s[i]=='?')s[i]='!'; } string temp=""; //int q=0; for(i=0;i<s.size();i++) { if(s[i]!=' ') { temp+=s[i]; } else { if(temp!=""){ b.push_back(temp);//将单词或者数字依次存储在b中; temp=""; } //cout<<b[q]<<"*"<<endl; //q++; } } // cout<<q<<endl; if(temp!="")b.push_back(temp);//存储第m-1个 //int w=b.size(); //cout<<w<<endl; for(int j=0;j<b.size();j++) { if(b[j]=="I"||b[j]=="me")b[j]="you"; else if(b[j]=="can"||b[j]=="could") { if((j+1)<b.size()) { if(b[j+1]=="you") { b[j+1]=b[j]; b[j]="I"; //b[i+1]= } } } } for(i=0;i<b.size();i++) { cout<<b[i]; if(i==b.size()-1)break; if((b[i+1][0]>='0'&&b[i+1][0]<='9')||(b[i+1][0]>='a'&&b[i+1][0]<='z')||b[i+1][0]=='I') { printf(" "); } } printf("\n"); //cout<<n<<endl; b.clear();//清空数组b } return 0; }

浙公网安备 33010602011771号