PAT甲级刷题笔记(1)

1. 计算a+b(1001)

本题a,b的范围都是在正负1000000以内,数值不大,因此不必担心int溢出的问题,可以直接相加。难点在于输出,每隔三位要插入“,”。

我最开始是用int保存结果,通过存储%1000后的结果输出,但这样对一些特殊情况就通过不了。比如两个1000000相加,结果为200000,要准确控制输出几个0就很不方便。因此我改用string存储结果并输出,就解决了这一问题。

#include<iostream>
#include<string>
using namespace std;

int main(){
    int a,b;
    cin>>a>>b;    
    int sum=a+b;
    if(sum<0){
    //负数先处理符号问题,再转成正数,便于之后同一处理
        cout<<"-";
        sum*=-1;
    }
    //to_string()函数把其他类型转化成string,记得添加<string>头文件
    string s=to_string(sum);

    int n=s.length()%3;//n用来控制在第几位时要输出
    for(int i=0;i<s.length();i++){
        cout<<s[i];
        if((i+1-n)%3==0&&i<s.length()-1) cout<<",";
    }
    
    return 0;
}

语法收获:(1)测试用例输入a\b时,中间只能用空格,不能用逗号,否则会影响cin>>a>>b中b的读入;

(2)字符串转化函数to_string()。

2.洗牌机(1042)

这题的难点就在于如何正确地对数组操作,进行多次洗牌了。最直接的想法当然是先定义一个顺序的牌数组,再根据洗牌序列洗牌。但这样做的问题在于:定义一个char数组存储牌就比较费劲,洗牌时还要大量交换,更是繁琐。

但既然原牌组本身是有序的,可以直接用其序号代替其内容(花色与点数),对序号数组洗牌,根据最终洗牌的结果序列来输出即可。

如果想避免代码段中t1还是t2存储结果的判断带来的代码冗余,可以增加一段代码,每次洗牌后把t1结果都给t2。

#include<iostream>
using namespace std;

int main(){
    char flower[6]={"SHCDJ"};
    int K,num=0,i;
    int order[54],t1[54],t2[54];      
    //由于涉及多次洗牌,使用两个t数组轮流存储洗牌结果
    
    cin>>K;
    //完成第一次洗牌,num表示原牌组中的序号
    while(cin>>order[num]){    
        t2[order[num]-1]=num+1;
        num++;       
    }
    //完成剩余k-1次洗牌
    int flag=2;//现在是t2存储洗牌结果
    for(i=0;i<K-1;i++){
        if(flag==2) {
            for(num=0;num<54;num++){
                t1[order[num]-1]=t2[num];                
            }
            flag=1;
        }
        else{
            for(num=0;num<54;num++){
                t2[order[num]-1]=t1[num];                
            }
            flag=2;
        }
    }
    
    if(flag==1){
        for(i=0;i<54;i++){
        //s,n分别表示对应的花色和点数,对13点的情况要特别处理一下
            int s=t1[i]/13;
            int n=t1[i]%13;
            if(n==0) {n=13;s--;}
            cout<<flower[s]<<n;
            if(i!=53)cout<<" ";
        }
    }
    else{
        for(i=0;i<54;i++){
            int s=t2[i]/13;
            int n=t2[i]%13;
            if(n==0) {n=13;s--;}
            cout<<flower[s]<<n;
            if(i!=53)cout<<" ";
        }
    }
    
    return 0;
}

3. 最短路径(1046)

本题是判断环路上两点间的最短路径,我们只需要考虑从i-j和j-i的长度,选出其中最小值即可,但是常规的递增计算会超时。经过查看参考答案,解决方法是在读入数据时,定义辅助数组存储第i个点到第1个点的距离。这样,两点间的一个距离就可以直接用对应数组相减即可。

#include<iostream>
using namespace std;
#define N 100000
#define M 10000
int main(){
    int n,m,i,sum=0;
    int dis[N];
    int p1[M],p2[M];
    
    cin>>n;
    for(i=0;i<n;i++){
        cin>>dis[i];
        sum+=dis[i];
    }
    cin>>m;
    for(i=0;i<m;i++){
        cin>>p1[i]>>p2[i];
    }
    
    int t,j;
    for(i=0;i<m;i++){   
        int d=0;
        if(p1[i]>p2[i]){
            t=p1[i];
            p1[i]=p2[i];
            p2[i]=t;
        }
        if(p2[i]-p1[i]<n/2){
            for(j=p1[i];j<p2[i];j++){
                 d+=dis[j-1];            
            }
        }
        else{
            for(j=p2[i];j<=n;j++){
                 d+=dis[j-1];            
            }
            for(j=0;j<p1[i];j++){
                 d+=dis[j-1];            
            }
        }
        if(d<sum-d) cout<<d<<endl;
        else cout<<sum-d<<endl;
    }
    return 0;
}

4.A+BandC(1046)

这题难度较大,因为加数较大,容易溢出。开始考虑用string操作,但这样还得分+和-考虑,计算2遍,非常繁琐。参考网上答案,要注意到输入数据范围在[-2^63,2^63]范围内,考虑用long long存储(范围是[-2^63,2^63))。若a<0,b<0时sum>0,必定溢出,A+B肯定小于C;同理,a>0,b>0,sum<0,也一定溢出,a+b肯定大于C;不溢出时,正常比较即可。

但现在系统上增加了2^63的测试用例,用long long读入就会自动溢出变成-2^63,导致错误,这是需要后面继续解决的问题。

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;


int main(){
    
    int T,i;
    cin>>T;
    for(i=1;i<=T;i++){
        long long A,B,C,sum;
        cin>>A>>B>>C;
        sum=A+B;
        
        if(A>0&&B>0&&sum<0){
            //sum<0说明溢出了,sum一定大于C
            cout<<"Case #"<<i<<": true"<<endl;
        }
        else if(A<0&&B<0&&sum>0){
            //sum>0说明溢出了,sum一定小于C
            cout<<"Case #"<<i<<": false"<<endl;
        }
        else if(sum>C)   {
            cout<<"Case #"<<i<<": true"<<endl;
        }     
        else {
            cout<<"Case #"<<i<<": false"<<endl;
        }        
        
    }
    return 0;
}

语法:(1)注意几种类型的数据范围:如对4字节的int,共有32位,所以范围是[-2^31,2^31-1]

5. 多项式加法(1002)

本题难度不大,主要在于输出细节上的注意。要描述一个多项式,即要指明其每项的系数和指数,指数都是自然数,正好对应数组的下标,所以只需用数组存储每项的系数,加法操作直接对对应的系数值执行加减即可。注意以下问题:

(1)如何统计多项式和有几个非0项?我最开始是想根据读入数据时,读入了哪些项,结果就有几项。但这样忽略了相加后系数为0的情况,比如-1.5x和1.5X+2相加,结果只有1项。所以应当在相加结束后,再来统计多项式项数;

(2)输出格式的问题:不要在末尾多加空格,不应该在输出项数时就打印空格,这样会在项数为0时出错(这个输出错误找了好久o(╥﹏╥)o);

(3)审题,输出应该只保留一位小数。

#include<iostream>
#include <iomanip>
using namespace std;
#define N 1001

int main(){
    double coe[N]={0};
    int max=0,min=N,num=0;//存储最大次数
    int i,k;
    for(i=0;i<2;i++){
        cin>>k;
        int exp;
        double coeff;
        for(int j=0;j<k;j++){
            cin>>exp>>coeff;            
            coe[exp]+=coeff;
            //cout<<j<<" "<<coe[exp]<<endl;
            if(exp>max) max=exp;
            if(exp<min)min=exp;
        }
    }
   // cout<<max<<" "<<min<<endl;
    for(i=max;i>=min;i--){
       if(coe[i]!=0) num++;
    }
    cout<<num;//不能在这里加“ ”
    for(i=max;i>=min;i--){
        if(coe[i]!=0){
            //cout<<i<<" "<<fixed<<setprecision(1)<<coe[i];
            printf(" %d %.1f",i,coe[i]);
            //if(i>min) cout<<" ";
        }
    }
    return 0;
}

语法:(1)cout控制输出小数保留位数,cout<<i<<" "<<fixed<<setprecision(1)<<coe[i];记得添加头文件,或者直接用printf更方便。

6. 世界杯赔率(1011)

这题比较简单,就是一个3阶的二维数组,找出每行的最大值即可。按顺序读入,顺便记录下每行最大坐标即可,最后计算收益。

#include<iostream>
using namespace std;

int main(){
    double odds[3][3];
    int maxs[3]={0};//存储每局比赛的最大几率对应下标
    int i,j;
    double profit=0.65;
    
    for(i=0;i<3;i++){
        for(j=0;j<3;j++){
            cin>>odds[i][j];
            if(odds[i][j]>odds[i][maxs[i]]) maxs[i]=j;
        }
    }    
    for(i=0;i<3;i++){
        if(maxs[i]==0) cout<<"W ";
        else if(maxs[i]==1)cout<<"T ";
        else cout<<"L ";
        profit*=odds[i][maxs[i]];
    }
    profit=(profit-1)*2;
    printf("%.2f",profit);
    return 0;
}

7. 签到和签退(1006)

这题和之前做过的学生程序排序类似,思路都是先定义一个结构体存储每个人的ID和签到、签退时间信息。之后根据时间先后对结构体数组排序,找到最小签到和最大签退时间对应信息输出即可。

不过这题其实不需要排序,因为只涉及到找到两个最值,遍历一遍即可,可以进一步减少时间复杂度

排序方法:

#include<iostream>
#include<algorithm>
using namespace std;
#define N 100
typedef struct sign{
    string ID;
    int SignIn[3],SignOut[3];    
};

bool EarilTime(sign x,sign y){
    if(x.SignIn[0]!=y.SignIn[0]) return x.SignIn[0]<y.SignIn[0];
    else{
        if(x.SignIn[1]!=y.SignIn[1]) return x.SignIn[1]<y.SignIn[1];
        else return x.SignIn[2]<y.SignIn[2];
    }
}

bool LastTime(sign x,sign y){
    if(x.SignOut[0]!=y.SignOut[0]) return x.SignOut[0]>y.SignOut[0];
    else{
        if(x.SignOut[1]!=y.SignOut[1]) return x.SignOut[1]>y.SignOut[1];
        else return x.SignOut[2] > y.SignOut[2];
    }
}

int main(){
    int n,i;
    cin>>n;
    sign s[N];
    for(i=0;i<n;i++){
        cin>>s[i].ID;
        scanf("%d:%d:%d",&s[i].SignIn[0],&s[i].SignIn[1],&s[i].SignIn[2]);
        scanf("%d:%d:%d",&s[i].SignOut[0],&s[i].SignOut[1],&s[i].SignOut[2]);
    }
    sort(s,s+n,EarilTime);
    cout<<s[0].ID<<" ";
    sort(s,s+n,LastTime);
    cout<<s[0].ID;
    
    return 0;
}

遍历找最值:(把时间转化成秒,就可以直接比较大小)

#include <iostream>
#include <climits>
using namespace std;
int main() {
    int n, minn = INT_MAX, maxn = INT_MIN;
    scanf("%d", &n);
    string unlocked, locked;
    for(int i = 0; i < n; i++) {
        string t;
        cin >> t;
        int h1, m1, s1, h2, m2, s2;
        scanf("%d:%d:%d %d:%d:%d", &h1, &m1, &s1, &h2, &m2, &s2);
        int tempIn = h1 * 3600 + m1 * 60 + s1;
        int tempOut = h2 * 3600 + m2 * 60 + s2;
        if (tempIn < minn) {
               minn = tempIn;
               unlocked = t;
        }
        if (tempOut > maxn) {
            maxn = tempOut;
            locked = t;
            }
    }
    cout << unlocked << " " << locked;
    return 0;
}

8. 男生VS女生(1036)

这题和上面签到签退的题非常类似。都是用结构体存储个人信息,在读入时进行比较判断,保留当前分数最低的男生和分数最高的女生信息,最后输出即可。

#include<iostream>
using namespace std;

struct Student{
    char name[11],ID[11];
    char gender;
    int grade;    
}tem, male, female;
    
bool cmp(Student x,Student y){//x成绩小于y返回true
    return x.grade<y.grade;//题目保证成绩均不同
}

int main(){
    int n,i;
    male.grade=101;
    female.grade=-1;
    
    cin>>n;
    for(i=0;i<n;i++){
        cin>>tem.name>>tem.gender>>tem.ID>>tem.grade;
        //比较出男生最低成绩和女生最低成绩
        if(tem.gender=='M') {
            //tem.gender=="M"是错的,"M"表示一个字符串,而'M'才是字符(实际上是一个整型数)
            if(cmp(tem,male)==true) male=tem;
        }
        else{
            if(cmp(tem,female)==false) female=tem;
        }
    }
    
    if(female.grade!=-1) cout<<female.name<<" "<<female.ID<<endl;
    else cout<<"Absent"<<endl;
    if(male.grade!=101) cout<<male.name<<" "<<male.ID<<endl;
    else cout<<"Absent"<<endl;
    if(female.grade!=-1&&male.grade!=101) cout<<female.grade-male.grade;
    else cout<<"NA";
    
    return 0;
}    

语法:tem.gender=="M"是错的,"M"表示一个字符串,而'M'才是字符(实际上是一个整型数),才能与gender这个字符进行比较。

9. U型打印(1031)

本题关键在于确定n1和n2的值,根据n_{1}+n{_{2}}-2=N和n1=n3<=n2可以推导出:n2=(N+2)/3+(N+2)%3,n1=(N+2)/3。剩下就可以按行输出了。

#include<iostream>
#include<string>
using namespace std;

int main(){
    string s;
    cin>>s;    
    int len=s.length()+2;
    int n2=len/3+len%3,n1=len/3;
    //cout<<n1<<endl;
    //输出U的前面n1-1行
    for(int i=0;i<n1-1;i++){
        cout<<s[i];
        for(int j=0;j<n2-2;j++){
            cout<<" ";
        }
        cout<<s[len-3-i]<<endl;
    }
    for(int i=0;i<n2;i++){
        cout<<s[n1-1+i];
    }
    
    return 0;
}

10. 回文数判断(1019)

本题分成两部分:(1)完成进制转换,只需不断对b取余和除以b,直到为0即可;

(2)判断回文数,比较头尾对应位置是否相同,一旦不同就不是回文数。

#include<iostream>
using namespace std;

int main(){
    int N,b,num=0;    
    cin>>N>>b;
    
    int bit[100];//逆序存储进制转化后的各位的数字
     
    while(N!=0){
        bit[num]=N%b;
        N=N/b;
        
        num++;
    }
    //num此时存储进制转化后的位数
    int flag=1;
    for(int i=0;i<num/2;i++){
        if(bit[i]!=bit[num-1-i]) {
            cout<<"No"<<endl;
            flag=0;
            break;
           }
    }
    if(flag==1)cout<<"Yes"<<endl;
    for(int i=num-1;i>=0;i--){//逆序输出时为i--,否则发生段错误
        cout<<bit[i];
        if(i!=0)cout<<" ";
    }
    
    return 0;
}

11. 货币相加(1058)

参考时间相加和进制转化的相关思想,先将货币全部转化成以最小的Knut为单位进行相加,再类似于进制转化,不断模和除以相应的转化大小即可。注意:要与有较大的测试用例,题目中说Gallon最大可到10^7,再转化为Knut后大小为27*19*10^7的大小,所以应该用long long型存储。

#include<iostream>
using namespace std;

int main(){
    long long Gal,Sick,Knut;
    long long  sum=0;
    for(int i=0;i<2;i++){
        scanf("%lld.%lld.%lld",&Gal,&Sick,&Knut);
        sum+=Gal*29*17+Sick*29+Knut;
    }
    Knut=sum%29;
    sum/=29;
    Sick=sum%17;
    sum/=17;
    Gal=sum;
    cout<<Gal<<"."<<Sick<<"."<<Knut;
    
    return 0;
}

语法:若用scanf读入,注意long long型的读入占位符为%lld。

12. 福尔摩斯的约会(1061)

本题是遍历4个字符串,比较找到相同元素,难度不大。注意以下几点:

(1)星期判断,直接写1-7天的if或switch判断太麻烦了,可以用week字符串数组先预存周一到到日对应的字符缩写;

(2)输出注意:时间都要写成两位的形式,比如七点零九分,得写成07:09的形式;

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
using namespace std;

int mins(int a,int b){
    return a<b?a:b;
}
int main(){
    string d1,d2,s1,s2;
    cin>>d1>>d2>>s1>>s2;
    
    char week[7][4]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
    int i;
    int len1=mins(d1.length(),d2.length()),len2=mins(s1.length(),s2.length());
    for(i=0;i<len1;i++){
        if(d1[i]==d2[i]&&d1[i]>='A'&&d1[i]<='G'){
            cout<<week[d1[i]-'A']<<" ";
            break;
        }
    }
    for(int j=i+1;j<len1;j++){
        if(d1[j]==d2[j]&&d1[j]>='0'&&d1[j]<='9'){
            cout<<0<<d1[j]<<":";//时间都要占满两位数
            break;
        }
        if(d1[j]==d2[j]&&d1[j]>='A'&&d1[j]<='N'){
            cout<<10+d1[j]-'A'<<":";
            break;
        }
    }
    
    for(int j=0;j<len2;j++){
        if(s1[j]==s2[j]&&((s1[j]>='a'&&s1[j]<='z')||(s1[j]>='A'&&s1[j]<='Z'))){
            //if(j<10)cout<<0<<j;
            //else cout<<j;
            printf("%02d",j);
            break;
        }
    }
    return 0;
}

语法:(1)关于字符串存储,也可以用char s[70]这样的形式,读入方式为gets(s),长度为strlen(s);

(2)字符串数组week的说明,week[7][4],第二个维度至少是4,因为每个字符串还有‘\0’的结束标志占一位,输出第i行字符串,直接使用week[i]即可;

(3)打印输出:int保证强制两位输出,可用printf("%02d",j),这样就解决了0-9按两位输出的问题。

13.  科学计数法(1073)

本题主要是输出的情况比较多,要注意讨论,核心在于确定E的位置,确定E的大小,然后分为以下3种情况:

指数为正数,小数点右移:

(1)右移位数超过当前小数位数,需要在末尾补0,不需要输出小数点,如1.2E+10;

(2)右移位数少于当前小数位数,需要输出小数点,不需补0,如1.2345E+03;

指数为负数,小数点左移

(3)根据左移位数,在前面补上相应的零,要输出小数点。

其实对于指数位为0的特殊情况,也要单独考虑,但是测试用例没有考察这一情况。

#include<iostream>
#include<string>
using namespace std;

int main(){
    string s;
    cin>>s;
    if(s[0]=='-') cout<<'-';
    int e=0;//指示E的位置
    int flag=0;//确定指数位的符号
    int exp=0;//保存指数位大小
    while(s[e]!='E'){
        e++;
    }
    if(s[e+1]=='-') flag=1;
    
    for(int i=e+2;i<s.length();i++){
        exp=exp*10+s[i]-'0';
    }
    //cout<<exp<<endl;
    if(exp==0) {//指数为0的特殊情况
        for(int i=1;i<e;i++){
            cout<<s[i];
        }
        return 0;
    }
    if(flag==0){//指数为正时的输出
        int d=exp-e+3;
        if(d>=0){//此时不需输入小数点
            for(int i=1;i<e;i++){
                if(s[i]!='.')cout<<s[i];
            }
            for(int i=0;i<d;i++)  cout<<0;   
        }
        else{//此时需要输出小数点
            for(int i=1;i<e;i++){
                if(s[i]!='.')cout<<s[i];
                if(i==exp+2)cout<<'.';
            }
        }
    }
    else{//左移前面加0输出
        cout<<"0.";
        for(int i=1;i<exp;i++)  cout<<0;
        for(int i=1;i<e;i++){
               if(s[i]!='.')cout<<s[i];
            }
    }
    
    
    return 0;
}

14. 正确拼写(1005)

本题思路很简单,只要读入输入的数字(由于位数较多,应当用字符串读入),累加各个位数之和得到结果,逐位拼写即可(可以把结果再转化为字符串便于读取每一位)。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int main(){
    char N[102];
    cin.getline(N,102);//pat不再支持gets(N)的用法,
    
    int len=strlen(N);//字符串长度不包括末尾的\0
    char num[10][10]={"zero","one","two","three","four","five","six","seven","eight","nine"};
    int sum=0;
    for(int i=0;i<len;i++){
        sum+=N[i]-'0';
    }
    
    string s=to_string(sum);
    
    for(int i=0;i<s.length();i++){       
        cout<<num[s[i]-'0'];//这里的s[i]是字符数字,必须减去‘0’才能得到对应的数字
        if(i<s.length()-1) cout<<" ";
    }
    return 0;
}

语法:(1)关于字符串读入建议还是使用string直接cin,pat已经不再支持gets()的读入方法,或者可以用cin.getline(s,长度)的用法。strlen()要添加头文件<cstring>

(2) 注意字符数字转化为int类型时不再对应0-9,而是相应的acill码,否则很可能越界出错

15. 密码改正(1035)

本题其实思路比较简单,遍历每条密码,修改对应的字符即可。其实如果不要求先输出修改密码个数的话,只需要两个字符串变量即可,改完即可输出。但是题目要求先输出修改个数,只能定义结构体数组先存储所有结果,统计完之后再输出。定义一个标志变量,表示字符串是否被修改了。

#include<iostream>
using namespace std;

struct Account{
    string ID,key;
};
int main(){
    int n;
    cin>>n;
    Account acc[1002];
    int order[1002];
    int num=0;//统计修改个数
    for(int i=0;i<n;i++){
        cin>>acc[i].ID>>acc[i].key;
        int flag=0;
        for(int j=0;j<acc[i].key.length();j++){
            
            if(acc[i].key[j]=='1') {
                acc[i].key[j]='@';flag=1;
            }
            else if(acc[i].key[j]=='0') {
                acc[i].key[j]='%';flag=1;
            }
            else if(acc[i].key[j]=='l') {
               acc[i].key[j]='L';flag=1;
            }
            else if(acc[i].key[j]=='O') {
                acc[i].key[j]='o'; flag=1;
            }
        }
        if(flag==1) {//已修改密码的记录下其序号,并把个数+1
            order[num]=i;
            num++;
        }
    }
    if(num!=0){
        cout<<num<<endl;
        for(int i=0;i<num;i++){
            cout<<acc[order[i]].ID<<" "<<acc[order[i]].key<<endl;
        }
    }
    else{
        if(n==1)
        cout<<"There is 1 account and no account is modified";
        else cout<<"There are "<<n<<" accounts and no account is modified";
    }
    return 0;
}

参考解答:除结构体之外,还可以用vector存储多条字符串

#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
scanf("%d", &n);
vector<string> v;
for(int i = 0; i < n; i++) {
string name, s;
cin >> name >> s;
int len = s.length(), flag = 0;
for(int j = 0; j < len; j++) {
switch(s[j]) {
case '1' : s[j] = '@'; flag = 1; break;
case '0' : s[j] = '%'; flag = 1; break;
case 'l' : s[j] = 'L'; flag = 1; break;
case 'O' : s[j] = 'o'; flag = 1; break;
}
}
if(flag) {
string temp = name + " " + s;
v.push_back(temp);
}
}
int cnt = v.size();
if(cnt != 0) {
printf("%d\n", cnt);
for(int i = 0; i < cnt; i++)
cout << v[i] << endl;
} else if(n == 1) {
printf("There is 1 account and no account is modified");
} else {
printf("There are %d accounts and no account is modified", n);
}
return 0;
}

16. 找公共后缀(1077)

思路是逐个读入字符串,与第一条字符串比较末尾序列,找出这些公共末尾序列长度的最小值,一旦出现为0的情况,则没有公共后缀,直接输出“nai”后返回;否则根据后缀长度输出末尾序列即可。

#include<iostream>
#include<cstring>
using namespace std;

int main(){
    int N;
    cin>>N;
    cin.get();//读入回车,保证后面读入字符串不出错
    char temp[257];
    //char tail[257];
    cin.getline(temp,257);
    int sublen=strlen(temp);//存储最短公共子序列长度
    
    for(int i=0;i<N-1;i++){
        char str[257];
        cin.getline(str,257);         
        int t=strlen(temp);
        int s=strlen(str);
        int num=0;
        while(temp[t-1]==str[s-1]&&t>0&&s>0&&num<=sublen){
            //tail[num]=str[s-1];
            num++;//统计公共尾序列长度   
            t--;
            s--;
        }
        if(num==0){
            cout<<"nai";
            return 0;
        }
        else{
            if(num<sublen) sublen=num;
        }
    }
    int len=strlen(temp);
    for(int i=0;i<sublen;i++){
        cout<<temp[len-sublen+i];
    }
    return 0;
}

17. 用中文读数字(1082)

这题我没有正确做出来,主要感觉处理起来太繁琐了,要根据序列长度情况决定什么时候输出“qian”,"bai","shi"等,还要考虑中间为0的情况。

在参考网络解答后,解决方法如下:(1)根据输出规则,4位数划分为1节,按节处理,分别用left\right指示各节的左右;

(2)根据输出的是当前节的第几位,决定在数字后加上千百十,个位不需输出;

(3)各节输出完成后,要考虑输出万或者亿,根据节数来输出,从右数第三节末尾输出亿,第2节末尾输出万;

(4)中间位为0的情况,用一个标志位flag处理。

#include<iostream>
using namespace std;

int main(){
    char num[10][10]={"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
    char wei[5][5]={"Shi","Bai","Qian","Wan","Yi"};
    string s;   
    cin>>s;
    //cout<<s<<endl;
    int len=s.length();
    int left=0,right=len-1;//left和right分别指示字符串的头尾位置
    if(s[0]=='-'){
        cout<<"Fu";
        left++;//指示到第一位数字
    }
    
    while(left+4<=right){
        right-=4;//控制left和right指示到同一节的首尾
    }
    while(left<len){//从左到右处理数字中的某一节
        bool flag=false;//标记是否有累计的0
        bool isPrint=false;//表示该节没有输出过其中的位
        while(left<=right){//处理这一节的输出
            if(left>0&&s[left]=='0'){
                flag=true;
            }
            else{
                if(flag==true){//如果存在累积的0
                    cout<<" ling";
                    flag=false;
                }
                if(left>0) cout<<" ";//非首位的话,前面要输出空格
                cout<<num[s[left]-'0'];//输出当前数字
                isPrint=true;//该节已有数字输出
                if(left!=right){//除了个位以外,其它位需要输出十百千
                    //right指示着本节的个位,left从头部右移
                    cout<<" "<<wei[right-left-1];
                }
            }
            left++;
        }
        if(isPrint==true&&right!=len-1){//只要不是最后一节,就要输出万或亿
            //根据所在节数(len-1-right)输出,从右数第3节输出亿,第2节输出万
            //isPrint==true是避免1,0000,1111这种第2节全为0的数输出万
            cout<<" "<<wei[(len-1-right)/4+2];
        }
        right+=4;//进入下一节
    }
    
    return 0;
}

18.  德才论(A1062)

这一题关键在于先根据德行和才能得分分类,再分别对其排序,但按这条思路就需要定义4个数组进行存储,还要再读入后复制到对应的组内,这样处理起来非常繁琐,而且还容易爆栈(当然,这应该是因为我把大型数组定义再来main函数内)。

参考网络解答,我们可以给结构体增加一个类别属性,既然输出是按从圣人到愚人的顺序,那我们在定义排序函数时,可以依次按类别、总分、德行、序号排序,这样只需一个数组处理,空间也更少。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;

struct Man {
    char ID[20];
    int Virtue, Talent,flag;//flag表示所属的类
}man[100010];

bool cmp(Man x, Man y) {
    int Xsum = x.Virtue + x.Talent, Ysum = y.Virtue + y.Talent;
    if(x.flag!=y.flag) return x.flag < y.flag;//先排序号小的类
    else if (Xsum != Ysum) return Xsum > Ysum;
    else if(x.Virtue != y.Virtue) return x.Virtue > y.Virtue;
    else  return strcmp(x.ID, y.ID) < 0;
}


int main() {
    int n, L, H;   
    cin >> n >> L >> H; 
    int m=n;
    for (int i = 0; i < n; i++) {
        cin >> man[i].ID >> man[i].Virtue >>man[i].Talent;
        if (man[i].Virtue <L || man[i].Talent<L) {
            m--;
            man[i].flag=5;
            //continue;
        }
        else if (man[i].Virtue >= H && man[i].Talent >= H) {
             man[i].flag=1;
        }
        else if (man[i].Virtue >= H  && man[i].Talent < H) {
           man[i].flag=2;
        }
        else if (man[i].Virtue >= man[i].Talent && man[i].Virtue < H &&  man[i].Talent < H) {
           man[i].flag=3;
        }
        else {
            man[i].flag=4;
        }
    }
    
    sort(man, man + n, cmp);
    cout<<m<<endl;
    for(int i=0;i<m;i++){
        cout<<man[i].ID<<" "<<man[i].Virtue<<" "<<man[i].Talent<<endl;
        //(i<m-1)cout<<endl;
    }
    return 0;
}

语法:复习strcmp(s1,s2)函数,s1<s2返回-1,s1=s2返回0,s1>s2返回1。

19. 最佳排序(A1012) 

本题的难点在于:(1)如何根据学生ID查询到其对应的成绩;(2)如何取得4个排名并进行输出。

参考网上解答后,注意到ID全是6位数字,所以可以直接用Rank[1000000][4]存储ID对应的4个排名,并考虑到4个排名的优先级,按顺序存储A\C\M\E。4个排名则需要对成绩作4次排序,每次排序后存储排名(注意同分的排名应该相同)

#include<iostream>
#include<algorithm>
using namespace std;

int t = 0;
int Rank[1000000][4] = { 0 };//存储排名
struct Students {
    int ID;
    int grade[4];//依次存储A/C/M/E成绩
}stu[2010];

bool cmp(Students x, Students y) {
    return x.grade[t] > y.grade[t];
}

int main() {
    int N, M;
    cin >> N >> M;
  
    for (int i = 0; i < N; i++) {
        cin >> stu[i].ID >> stu[i].grade[1] >> stu[i].grade[2] >> stu[i].grade[3];
        stu[i].grade[0] = (stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3]) / 3;
    }
    for (t = 0; t < 4; t++) {
        sort(stu, stu + N, cmp);
        Rank[stu[0].ID][t] = 1;
        for (int i = 1; i < N; i++) {
            if (stu[i - 1].grade[t] == stu[i].grade[t]) {
                //若分数相等,则排名应该相同
                Rank[stu[i].ID][t] = Rank[stu[i - 1].ID][t];
            }
            else {
                //否则排名应该为其数组下标+1
                Rank[stu[i].ID][t] = i + 1;
            }
        }
    }
    int num;
    char subject[5] = { 'A','C','M','E' };
    for (int i = 0; i < M; i++) {
        cin >> num;
        if (Rank[num][0] == 0) cout << "N/A" << endl;
        else {
            int tem = 0;
            for (int j = 1; j < 4; j++) {
                if (Rank[num][j] < Rank[num][tem]) tem = j;
            }
            cout << Rank[num][tem] << " " << subject[tem] << endl;
        }
    }

    return 0;
}

 语法:(1)若题目要求计算4舍5入后的结果,则可以用

stu[i].grade[0] =round( (stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3]) / 3)+0.5;

round保留四舍5入后的结果

(2)Rank数组不可以命名为rank,会与关键字发生重复;

(3)Rank这种很大的数组应该定义在main函数外部,否则会发生段错误。因为全局变量在静态存储区内分配内存,而局部变量是在栈内分配内存空间的。C语言编写的程序会在运行期间创建一个栈堆段,用来保存函数的调用关系和局部变量。而在main函数内部定义大数组相当于在栈内需要一个很大的空间,会造成栈的溢出。
因此,当我们需要定义一个极大的数组时,最好在mian 函数外部定义这个大数组。

20.  电话账单(A1016)

这题相当繁琐,难点主要在于:

(1)正确匹配用户的每次通话记录。通过设置flag表示on/off-line状态,以及排序可以绑定一次通话的两条记录在相邻位置上;

(2)计算每次通话的电话费,以及总费用。算钱的难点在于,由于每个小时的费用都不全相同,所以不能简单的求出时间差×单价,我是写了一个计算单日内任意两时刻内的费用的函数,若跨天,则分情况调用。当然也可以从开始时间逐分钟累加到结束时间,同时计费。

(3)有的用户没有正确的通话账单不需要输出,有的用户有多次消费记录,要正确按照格式输出。设置tem作为输出标志,用于给有多次消费的用户在正确时刻输出总账。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int prices[24];
struct Customer{
    char name[30];
    int mon,day,hour,min;
    int flag;//0表示online,1表示offline
}cust[1010];

bool cmp(Customer x,Customer y){
    if(strcmp(x.name,y.name)!=0) return strcmp(x.name,y.name)<0;
    else if(x.mon!=y.mon) return x.mon<y.mon;
    else if(x.day!=y.day) return x.day<y.day;
    else if(x.hour!=y.hour) return x.hour<y.hour;
    else return x.min<y.min;
}

double amount(int h1,int m1,int h2,int m2){
    //计算小时内的金额
    double cost=0;
    if(h1==h2){
       cost = (m2-m1)*prices[h1];
     }            
     else{
       cost=(60-m1)*prices[h1];
       for(int j=h1+1;j<h2;j++){
          cost += prices[j]*60;
      }
       cost+=m2*prices[h2];                    
    }
    return cost/100.;
}


int main(){
    
    for(int i=0;i<24;i++){
        scanf("%d",&prices[i]);
    }
    int n;
    scanf("%d",&n);
    char str[30];
    for(int i=0;i<n;i++){
        scanf("%s %d:%d:%d:%d %s",cust[i].name,&cust[i].mon,&cust[i].day,&cust[i].hour,&cust[i].min,str);
        if(strcmp(str,"on-line")==0) {
            cust[i].flag=0;
            //printf("%d",cust[i].flag);
        }        
        else  cust[i].flag=1;
    }
    sort(cust,cust+n,cmp);
    int tem=0;//用作每个用户开始输出标志
    //int out=0;
    double sum=0;
    for(int i=0;i<n-1;i++){
        if(strcmp(cust[i].name,cust[i+1].name)==0){
            
            if(cust[i].flag==0 && cust[i+1].flag==1){
                double cost=0;
                //是否有不同月份
                if(tem==0) {
                    printf("%s %02d\n",cust[i].name,cust[i].mon);
                    //out=1;
                    tem=1;
                }
                
                printf("%02d:%02d:%02d %02d:%02d:%02d",cust[i].day,cust[i].hour,cust[i].min,cust[i+1].day,cust[i+1].hour,cust[i+1].min);
                int time =cust[i+1].day*1440+cust[i+1].hour*60+cust[i+1].min - (cust[i].day*1440+cust[i].hour*60+cust[i].min);
                if(cust[i+1].day!=cust[i].day){//跨天计费
                    cost =amount(cust[i].hour,cust[i].min,23,59)+prices[23]/100.;
                   cost +=(amount(0,0,23,59)+prices[23]/100.)*(cust[i+1].day-cust[i].day-1);
                    cost +=amount(0,0,cust[i+1].hour,cust[i+1].min);
                }                          
                else{
                    cost= amount(cust[i].hour,cust[i].min,cust[i+1].hour,cust[i+1].min);                   
                }                    
                printf(" %d $%.2f\n",time,cost);
                sum+=cost;                
             }           
         }
        
       else {//切换到下一个用户时重置标记
            if(tem==1) printf("Total amount: $%.2f\n",sum);
            tem=0;
            sum=0;
        }
    }
    //如果tem=1,.说明最后一个用户存在有效的账单,他还没有输出Total amount
    if(tem==1)printf("Total amount: $%.2f\n",sum);    
    return 0;
}

语法:(1)注意审题,开始没注意到用户名最长为20字符的要求,只设置了10个数组长,导致后3个测试点卡了很久o(╥﹏╥)o;

(2)控制输出格式:要控制整型的输出位数,使用%md,m表示输出位数,不足在前面补0,否则正常输出。

21. PAT排名(A1025)

这题难度不大,关键在实现本地排名和总排名。在完成一个考试地点的信息读入后,就可以对这一块数据进行排序了,得到本地排名。全部地点读完后,再进行总排名,最后根据总排名输出即可。要小心的地方是本地排名时sort的范围。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

struct Testee{
    char ID[15];
    int grade,location;
    int FinRank,LocRank;
}T[30010];

bool cmp(Testee x,Testee y){
    if(x.grade!=y.grade) return x.grade > y.grade;
    else return strcmp(x.ID,y.ID)<0;
}

int main(){
    int n;
    cin>>n;
    int k,num=0;
    for(int i=0;i<n;i++){
        cin>>k;
        for(int j=0;j<k;j++){
            cin>>T[num].ID>>T[num].grade;
            T[num].location = i+1;
            num++;            
        }
        //sort(start,end,cmp),start是起始位置,end是最后一位+1
        sort(T+num-k,T+num,cmp);
        T[num-k].LocRank=1;
        for(int j=num-k+1;j<num;j++){
            if(T[j].grade==T[j-1].grade) T[j].LocRank =T[j-1].LocRank;
            else T[j].LocRank = j-(num-k)+1;
        }
    }
    sort(T,T+num,cmp);
    T[0].FinRank=1;
    cout<<num<<endl;
    cout<<T[0].ID<<" "<<T[0].FinRank<<" "<<T[0].location<<" "<<T[0].LocRank<<endl;
    for(int j=1;j<num;j++){
        if(T[j].grade==T[j-1].grade) T[j].FinRank =T[j-1].FinRank;
        else T[j].FinRank = j+1;
        cout<<T[j].ID<<" "<<T[j].FinRank<<" "<<T[j].location<<" "<<T[j].LocRank<<endl;
    }
    
    
    return 0;
}

语法:sort(start,end,cmp),start是起始位置,end是最后一位+1

22. 列表排序(1028)

这题比较简单,写3个cmp函数,根据C值选用即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

struct Students{
    int ID,grade;
    char name[10];
}stu[100010];

bool cmp1(Students x,Students y){
    return x.ID<y.ID;
}

bool cmp2(Students x,Students y){
    if(strcmp(x.name,y.name)!=0) return strcmp(x.name,y.name)<0;
    else return x.ID<y.ID;
}

bool cmp3(Students x,Students y){
    if(x.grade!=y.grade) return x.grade<y.grade;
    else return x.ID<y.ID;
}

int main(){
    int n,c;
    cin>>n>>c;
    for(int i=0;i<n;i++){
        cin>>stu[i].ID>>stu[i].name>>stu[i].grade;
    }
    if(c==1){
        sort(stu,stu+n,cmp1);        
    }
    else if(c==2){
        sort(stu,stu+n,cmp2);
    }
    else{
        sort(stu,stu+n,cmp3);
    }
    for(int i=0;i<n;i++){
        //cout<<stu[i].ID<<" "<<stu[i].name<<" "<<stu[i].grade<<endl;
        printf("%06d %s %d\n",stu[i].ID,stu[i].name,stu[i].grade);
    }
    
    return 0;
}

23. 富豪排名(1055)

这题我开始的想法是先对所有人按年龄排名,每次查询时先确定对应的年龄范围内的所有人,再对这部分人按财富、年龄、姓名排序,最后进行输出。但这样会导致:每次查询后都破坏原先的有序年龄序列,因此需要复原(重排序或者借用辅助数组),过多的排序导致时间复杂度过大,在第二个测试点会超时。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

struct Man {
    char name[10];
    int age, wealth;
}stu[1010];

bool CmpAge(Man x, Man y) {
    //先按年龄对数组做排序
    return x.age < y.age;
}

bool CmpWealth(Man x, Man y) {
    //按财富、年龄、姓名的优先级排序
    if (x.wealth != y.wealth) return x.wealth > y.wealth;
    else if (x.age != y.age) return x.age < y.age;
    else return strcmp(x.name, y.name) < 0;
}

void AgeRange(int amin, int amax, int& low, int& high, int n) {
    for (int i = 0; i < n; i++) {
        if (stu[i].age >= amin) {
            low = i;
            break;
        }
    }
    if (low == -1) return;
    for (int i = n - 1; i >= low; i--) {
        if (stu[i].age <= amax) {
            high = i;
            break;
        }
    }
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    int num[1010], Amin[1010], Amax[1010];
    for (int i = 0; i < n; i++) {
        scanf("%s%d%d", stu[i].name, &stu[i].age, &stu[i].wealth);
    }
    for (int i = 0; i < m; i++) {
        scanf("%d%d%d", &num[i], &Amin[i], &Amax[i]);
    }
    sort(stu, stu + n, CmpAge);
    int low = -1, high = -1;
    for (int i = 0; i < m; i++) {
        printf("Case #%d:\n", i + 1);

        AgeRange(Amin[i], Amax[i], low, high, n);
        printf("%d %d %d %d\n", low, high, Amin[i], Amax[i]);
        if (low == -1 || high == -1) {
            printf("None\n");
        }
        else {
            sort(stu + low, stu + high + 1, CmpWealth);
            int tem;
            num[i] < (high - low + 1) ? tem = num[i] : tem = (high - low + 1);
            for (int j = 0; j < tem; j++) {
                printf("%s %d %d\n", stu[low + j].name, stu[low + j].age, stu[low + j].wealth);
            }
        }
        low = -1;
        high = -1;
       sort(stu + low, stu + high + 1, CmpAge);	
    }

    return 0;
}

参考网络解答后,要注意到每次查询最多只查询100人,因此,可以将原数组中同年龄的财富前100名存储到辅助数组中,每次查询时采用遍历搜索符合年龄段要求的,这样查询的时间复杂度可以降低为线性时间。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

struct Man{
    char name[10];
    int age,wealth;
}stu[100010],valid[100010];
//valid存储所有人在各自年龄中财富值前100名内的人

int Age[210]={0};//存储各年龄的人数

bool CmpWealth(Man x,Man y){
    //按财富、年龄、姓名的优先级排序
    if(x.wealth!=y.wealth) return x.wealth>y.wealth;
    else if(x.age!=y.age) return x.age<y.age;
    else return strcmp(x.name,y.name)<0;
}


int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    
    for(int i=0;i<n;i++){
        scanf("%s%d%d",stu[i].name,&stu[i].age,&stu[i].wealth);
        
    }
    sort(stu,stu+n,CmpWealth);
    int validnum=0;//表示存放到valid数组中人数
    for(int i=0;i<n;i++){
        if(Age[stu[i].age]<100){
            Age[stu[i].age]++;
            valid[validnum++]=stu[i];
        }
    }
    int num,amax,amin;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&num,&amin,&amax);
        printf("Case #%d:\n",i+1);
        int Psnum=0;//统计本次查询已经输出人数
        for(int j=0;j<validnum&&Psnum<num;j++){
            if(valid[j].age>=amin&&valid[j].age<=amax){
                printf("%s %d %d\n", valid[j].name, valid[j].age, valid[j].wealth);
                Psnum++;
            }                       
        }
        if(Psnum==0) printf("None\n");               
    }
    
    return 0;
}

语法:(1)相同结构体变量之间可以直接赋值;

(2)字符串间复制,可以使用strcpy(s1,s2),把s2复制给s1。

24. PAT判断(1075)

这题的注意点在于对第一次编译未通过的提交(分值显示为-1),但在记分时应该要修改为0,而从未提交的情况则按没有分数(输出“-”)处理。由于题目中说,全场没有提交和没有通过编译的提交的考生不显示,所以在读入时要注意设置符号变量判断。

当然这题我做复杂了。因为我开始以为输入的考生号是散乱的,不一定从1-N到都有,所以又定义了一个备份数组存储实际存在的考生信息,实际上根据题意1-N号考生都有信息,可以直接读入后排序。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

struct Users{
    int ID=0;
    int sum=0;//sum统计总分
    int grade[5]={-1,-1,-1,-1,-1};
    int gradenum=0;//拿到满分的题目数量
}user[100010],valid[10010];

bool cmp(Users x,Users y){
    if(x.sum!=y.sum) return x.sum>y.sum;
    else if(x.gradenum!=y.gradenum) return x.gradenum>y.gradenum;
    else return x.ID<y.ID;
}

int main(){
    int n,k,m;
    scanf("%d%d%d",&n,&k,&m);
    int score[6]={0};
    for(int i=0;i<k;i++){
        scanf("%d",&score[i]);
    }
    int num,t,mark;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&num,&t,&mark);                 
        if(mark>user[num].grade[t-1]){
            //更新该题分数
            //开始时,mark>-1表示有能耐通过编译的提交
            user[num].ID=1;//ID这里用作指示器,变为1表示这名学生存在有效成绩
            user[num].grade[t-1]=mark;
            if(user[num].grade[t-1]==score[t-1]) user[num].gradenum++;
        }
        if(mark==-1 && user[num].grade[t-1]==-1){
            //第一次编译错误后将分值修改为0分
            user[num].grade[t-1]=0;
        }
    }
    int j=0;
    for(int i=0;i<100010;i++){
        if(user[i].ID==1) {
            valid[j]=user[i];
            valid[j].ID=i;
            for(int x=0;x<k;x++){
                //printf(" %d",valid[j].grade[x]);
                if(valid[j].grade[x]>=0) valid[j].sum+=valid[j].grade[x];
            }
            j++;
           // printf("\n");
        }
    }
    //printf("j=%d\n",j);   
    sort(valid,valid+j,cmp);
    //第一名单独输出
    int rank=1;
    printf("%d",rank);
    printf(" %05d %d",valid[0].ID,valid[0].sum);
    for(int x=0;x<k;x++){
            if(valid[0].grade[x]>=0) printf(" %d",valid[0].grade[x]);
            else printf(" -");
    }
    printf("\n");
    
    for(int i=1;i<j;i++){
        if(valid[i-1].sum==valid[i].sum) {
            printf("%d",rank);
        }
        else {
             printf("%d",i+1);
            rank=i+1;
        }
        printf(" %05d %d",valid[i].ID,valid[i].sum);
        for(int x=0;x<k;x++){
            if(valid[i].grade[x]>=0) printf(" %d",valid[i].grade[x]);
            else printf(" -");
       }
        printf("\n");
    }
    
    return 0;
}

修改后代码如下: 

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

struct Users{
    int flag=0,ID;
    int sum=0;//sum统计总分
    int grade[5];
    int gradenum=0;//拿到满分的题目数量
}user[10010];

void init(int n){//初始化
    for(int i=1;i<=n;i++){
        user[i].ID=i;
        memset(user[i].grade,-1,sizeof(user[i].grade));
    }
    
}

bool cmp(Users x,Users y){
    if(x.flag!=y.flag) return x.flag>y.flag;
    else if(x.sum!=y.sum) return x.sum>y.sum;
    else if(x.gradenum!=y.gradenum) return x.gradenum>y.gradenum;
    else return x.ID<y.ID;
}

int main(){
    int n,k,m;
    scanf("%d%d%d",&n,&k,&m);
    init(n);
    int score[6]={0};
    for(int i=0;i<k;i++){
        scanf("%d",&score[i]);
    }
    int num,t,mark;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&num,&t,&mark);                 
        if(mark>user[num].grade[t-1]){
            //更新该题分数
            //开始时,mark>-1表示有能耐通过编译的提交
            user[num].flag=1;//ID这里用作指示器,变为1表示这名学生存在有效成绩
            user[num].grade[t-1]=mark;
            if(user[num].grade[t-1]==score[t-1]) user[num].gradenum++;
        }
        if(mark==-1 && user[num].grade[t-1]==-1){
            //第一次编译错误后将分值修改为0分
            user[num].grade[t-1]=0;
        }
    }
    for(int i=1;i<=n;i++){      
            for(int x=0;x<k;x++){
                //printf(" %d",valid[j].grade[x]);
                if(user[i].grade[x]>=0) user[i].sum+=user[i].grade[x];
            }        
    }
    //printf("j=%d\n",j);   
    sort(user+1,user+n+1,cmp);
    //第一名单独输出
    int rank=1;
    printf("%d",rank);
    printf(" %05d %d",user[1].ID,user[1].sum);
    for(int x=0;x<k;x++){
            if(user[1].grade[x]>=0) printf(" %d",user[1].grade[x]);
            else printf(" -");
    }
    printf("\n");
    
    for(int i=2;i<=n;i++){
        if(user[i].flag==0) break;
        if(user[i-1].sum==user[i].sum) {
            printf("%d",rank);
        }
        else {
             printf("%d",i);
            rank=i;
        }
        printf(" %05d %d",user[i].ID,user[i].sum);
        for(int x=0;x<k;x++){
            if(user[i].grade[x]>=0) printf(" %d",user[i].grade[x]);
            else printf(" -");
       }
        printf("\n");        
    }
    
    return 0;
}

语法:(1)int a[5]={-1};这样的初始法只把第一个元素初始化为-1,其余元素都默认初始化为0,可以用memset吧整个数组值变为-1或0.(不可赋值为1,因为memset是按字节赋值)

(2) 对于复杂的结构体初始化,可以选择定义构造函数。

25. 成绩列表(1083)

简单题,直接按成绩降序排列,在遍历查找指定成绩范围的信息输出即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct Student{
    char name[12],ID[12];
    int grade;
}stu[110];

bool cmp(Student x, Student y){
    return x.grade>y.grade;
}

int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%s%s%d",stu[i].name,stu[i].ID,&stu[i].grade);        
    }
    int min,max;
    scanf("%d%d",&min,&max);
    sort(stu,stu+n,cmp);
    int flag=0;
    for(int i=0;i<n;i++){
        if(stu[i].grade<=max && stu[i].grade>=min){
            printf("%s %s\n",stu[i].name,stu[i].ID);
            flag=1;
        }
        if(stu[i].grade<min) break;
    }
    if(flag==0) printf("NONE\n");
    
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值