1080. MOOC期终成绩
题目分析:
这道题目,主要需要考虑清楚如何高效迅速地计算完成,明确快速查照的方法。有以下几个方面可以注意来提高计算速度:
- 仅当编程成绩大于等于200时,采可能及格,所以小于200的不用保存,减少之后查找匹配学号时的数组大小。
- 在统计期中、期末成绩时,需要对学号进行匹配,那么就需要在前面的列表里查找,如果遍历的话整体时间复杂度就太高了,这里需要采用二分查找,为此需要首先把前面生成的数组进行排序,按学号字典序升序排列即可。
- 统计期末成绩,简单运算就可以知道,34分以下不可能及格,所以也可以不去进行比较,直接跳过。
另外,题目输出时有并列的话是按并列排名输出的比如并列第一名就会都输出1,需要注意一下。
源代码
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef struct student_info{
char id[21];
int pScore=-1; //编程成绩
int mScore=-1; //期中成绩
int fScore=-1; //期末成绩
int Tot=-1; //总评
}info;
bool cmp(const info& n1,const info& n2){
if(n1.Tot!=n2.Tot) return n1.Tot>n2.Tot;
else return(strcmp(n1.id,n2.id)<0);
}
bool cmp1(const info& p1,const info& p2){
return strcmp(p1.id,p2.id)<0; //按姓名字母升序排列
}
int binsearch(char*arr,info* list,int lo,int hi){
int mid;
while(lo<=hi){
int mid=(lo+hi)>>1;
int compare=strcmp(arr,list[mid].id);
if(compare<0) hi=mid-1;
else if(compare>0) lo=mid+1;
else return mid;
}
return -1;
}
int main()
{
int prog_attend,mid_attend,final_attend;
scanf("%d %d %d",&prog_attend,&mid_attend,&final_attend);
info * reportList=new info[prog_attend]; //合格人数不可能超过有编程成绩的人数
char stuID[21];
int pscore,mscore,fscore;
int count=0;
for(int i=0;i<prog_attend;++i){
scanf("%s %d",stuID,&pscore);
if(pscore>=200){
strcpy(reportList[count].id,stuID);
reportList[count++].pScore=pscore;
}
}
std::sort(reportList,reportList+count,cmp1); //按姓名排序,便于查找
for(int i=0;i<mid_attend;++i){
scanf("%s %d",stuID,&mscore);
int order;
if((order=binsearch(stuID,reportList,0,count-1))>=0){ //遇到在线编程作业合格者
reportList[order].mScore=mscore;
}
}
for(int i=0;i<final_attend;++i){
scanf("%s %d",stuID,&fscore);
if(fscore<34) continue;
int order;
if((order=binsearch(stuID,reportList,0,count-1))>=0){
reportList[order].fScore=fscore;
}
}
for(int i=0;i<count;++i){
if(reportList[i].mScore<=reportList[i].fScore)
reportList[i].Tot=reportList[i].fScore;
else reportList[i].Tot=((double)reportList[i].mScore*0.4+(double)reportList[i].fScore*0.6)+0.5;
}
std::sort(reportList,reportList+count,cmp); //再按分数排序
for(int i=0;i<count;++i){
if(reportList[i].Tot<60) break;
printf("%s %d %d %d %d\n",reportList[i].id,reportList[i].pScore,
reportList[i].mScore,reportList[i].fScore,reportList[i].Tot);
}
delete []reportList;
return 0;
}
1081. 检查密码
题目分析:
首先判断密码的长度,不合格直接输出,之后再根据字母、数字的情况进行判断输出就可以。
但是有一个问题要注意,题目给的密码可能是包含空格的啊,所以不能用scanf %s,可以采用读取整行的函数来解决。
源代码
#include <cstdio>
#include <cstring>
#include <cctype>
void check(char* arr){
int len=strlen(arr);
if(len<6) {
printf("Your password is tai duan le.\n");
return;
}
bool HasNum=false,HasAlpha=false;
for(int i=0;i<len;++i){
if(isalpha(arr[i])) HasAlpha=true;
else if('0'<=arr[i]&&arr[i]<='9') HasNum=true;
else if(arr[i]!='.'){
printf("Your password is tai luan le.\n");
return;
}
}
if(HasAlpha&&!HasNum){
printf("Your password needs shu zi.\n");
return ;
}
else if(HasNum&&!HasAlpha){
printf("Your password needs zi mu.\n");
return;
}
printf("Your password is wan mei.\n");
}
int main()
{
int num;
scanf("%d",&num);
char pw[100];
while(num--){
getchar();
scanf("%[^\n]",pw); //果然,题目给的数据里存在以包含空格的字符串
check(pw);
}
return 0;
}
1082. 射击比赛
题目分析:
直接先用double变量存储各组x,y计算出的距离,然后再读取的同时记录下当前最好、最坏成绩以及对应的ID。
源代码
#include <cstdio>
#include <cmath>
int main()
{
int num,id,coordiX,coordiY;
double dist;
scanf("%d",&num);
int bestID,worstID;
double bestGrades=300.0,worstGrades=-1.0;
for(int i=0;i<num;++i){
scanf("%d %d %d",&id,&coordiX,&coordiY);
dist=sqrt((double)coordiX*coordiX+(double)coordiY*coordiY);
if(dist>worstGrades){
worstGrades=dist;
worstID=id;
}
if(dist<bestGrades){
bestGrades=dist;
bestID=id;
}
}
printf("%04d %04d",bestID,worstID);
return 0;
}
1083. 是否存在相等的差
题目分析:
用一个数组存储各个差出现的次数,下标0,1,2.。n-1分别对应于差为0,1,2…n-1(差最大为n-1)的情况。
在计算差时,由于数据读入的次序恰好就是每张牌正面对应的值,所以直接用读入的值与读入次序运算即可求得差。最后然后逆向从高到低进行判断,如果数组里的值大于1,就表示至少有两个卡片差相等,可以输出。
源代码
#include <cstdio>
#include <cstdlib>
int main()
{
int num;
scanf("%d",&num);
int *gap=new int[num]; //差最大就是num-1,故至多有num个不同的差
for(int i=0;i<num;++i)
gap[i]=0;
int value;
for(int i=0;i<num;++i){
scanf("%d",&value);
gap[abs(value-i-1)]++;
}
for(int i=num-1;i>-1;i--)
if(gap[i]>1) //根据题目要求,需要满足有差相等故数组值至少为2才允许输出
printf("%d %d\n",i,gap[i]);
delete [] gap;
return 0;
}
1084. 外观数列
题目分析:
首先要分析清楚题意,计算下一项的方法是,从前一项第一个字符开始,不妨设为’2’吧,往后逐项观察直到发现不同的字符,然后统计相同的字符数目,这里我们假设从第一个字符开始连续出现共5个2,第6项是’4’,所以外观数列下一项的头两个字符为’2’和’5’,之后再重复相同的方法,看有多少个连续的4’…
求外观数列下一项本质上是将前一项分成若干段,每段的都是同一个字符,然后统计他们各自是什么字符以及连续出现次数。
源代码
#include <iostream>
#include <string>
int main()
{
using namespace std;
int d,num;
scanf("%d %d",&d,&num);
string arrPre,arrNew="";
arrPre=d+'0'; //初始只有一个元素 ,数字对应的ASCII码
int round=0;
int lenPre=1; //统计前一项总长度
int pre,showTimes,count; //前一项中某个对应的字符、连续出现次数,以及相对是第几个不同字符
for(round=0;round<num-1;++round){
count=0; //统计的相同元素数
pre=arrPre[0];
showTimes=1;
for(int i=1;i<lenPre;++i){
if(arrPre[i]==pre)
showTimes++; //统计段内相同字符出现次数
else{
arrNew+=pre; //字符
arrNew+=showTimes+'0'; //出现的次数
count+=2;
pre=arrPre[i]; //更新pre的值
showTimes=1; //重置为1
}
}
arrNew+=pre; //对前一项末尾字符情况进行记录
arrNew+=showTimes+'0';
count+=2;
lenPre=count; //更新前驱信息
arrPre=arrNew;
arrNew="\0"; //将新数组重新置为空
}
cout<<arrPre;
return 0;
}