PAT乙级做题部分总结

做题时候的一些想得比较多的记录

目录

目录

1008 数组元素循环右移问题

分析题目

要求N个元素的数组中所有元素右移M个,并且提出了移动数据次数最低的要求。
这就代表直接从N-M开始输出是不可取的,作为练习题我们可以尽可能地发散思维。如果考试的时候来不及,直接输出也是条捷径。

解决方法

有以下几种方法可以考虑:
1.直接输出
2.做宽数组,向后储存(相当于使用了两个数组)
3.三次逆置法(利用对称和vector的逆置,想法巧妙)
4.从N-M开始,隔M个替换

三次逆置法
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
 int N,M;
 cin>>N>>M;
 M=M%N;
 vector<int> a(N);
 for(int i=0;i<N;i++) cin>>a[i];
 reverse(a.begin(),a.end());
 reverse(a.begin(),a.begin()+M);
 reverse(a.begin()+M ,a.end());
 for(int i=0;i<N;i++)
 {
   cout<<a[i];
   if(i != (n-1))
   cout<<' ';
 }
 return 0;
}

测试结果

个人感觉如果事先没有了解,还挺难想到的。如果有见过的基础,这就顺理成章了。

循环替换

可以发现,所有的循环都是将后M个提到最前面,剩下的全部右移M个即可。
考虑到不能使用另外的数组存放临时变量,也就是说每次我们只能使用temp来存放一个临时变量。
如果将后M个,从第N-M个开始,存放进变量temp,将前面每隔M个的变量都向后移M个(即在同余的序列号下,保存最后一个,其他依次转移到对应的位置,一个覆盖一个)
最后一定会回到temp的位置,将其放在对应的位置,结束该轮循环。
再从下一个(N-M+1)开始,存进temp……
以此类推,理论上就可以覆盖所有的数,都右移M个。

例如:N=6 , M=2, 123456->123436(temp=5)->121436->521436
     下一轮:521436->521434(temp=6)->521234->561234

但是这种算法有一个问题,就是:
如果当序列号<0(此时N、M互质),就停止循环,会出
现temp覆盖的位置,指向的数还没有被相应位置保存的情况。
如果不停止循环,可能出现一轮循环已经得到结果,继续循环会出错的情况。如N=8,M=3。
《算法笔记·上机训练实战指南》给出的建议是从N-M位开始,到N-M+d-1位结束,d为N、M的最小公倍数。

#include<iostream>
using namespace std;
int gcd(int n, int m){
    if(m==0) return n;
    else return gcd(m,n%m);
}
int main(){
    int N,M;
    cin>>N>>M;
    M=M%N;
    int a[100];
    int i=0;
    while(i<N){
        cin>>a[i];
        i++;
    }
    if(M!=0){
        int d=gcd(N,M);
        for(i=N-M;i<N-M+d;i++){
            int temp=a[i];
            int j;
            int pos=i;
            int next;
            do{
                next=(pos-M+N)%N;
                if(next!=i) a[pos]=a[next];
                else a[pos]=temp;
                pos=next;
            }while(pos!=i);
        }
    }
    for(i=0;i<N;i++){
        cout<<a[i];
        if(i!=N-1) cout<<' ';
    }
    return 0;
}

``
测试结果

1009 说反话

输入字符串,并使用存储容器存放分割后的单词,然后反向输出即可
主要注意字符串的相关操作:

  1. 输入带空格的字符串:getline(cin,s);
    cin.get()在其他编译器上可以运行,这里报错了
  2. 获取字符串的子串:
    s.substr(begin,num)
    strncpy(s1,s2,num):第一个参数是目录字符串;第二个参 数是源字符串;第三个参数是一个整数,代表要从源字符串拷贝到目标字符串中的字符数。
    通过改变s1,s2的指向,可以灵活拷贝

另外,有时int型的i和unsigned型的 size()结果不能直接比较,要进行强制类型转换

#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
    string s;
    getline(cin,s);
    vector<string> res;
    int i=0;
    int last=0;
    int size=s.size();
    for(;i<=size;i++){
        if(i==size||s[i]==' ') {
            string temp;
            res.push_back(s.substr(last,i-last));
            last=i+1;
            continue;
        }
        else continue;
    }
    for(i=res.size()-1;i>=0;i--){
        cout<<res[i];
        if(i!=0) cout<<' ';
    }
    return 0;
}

测试结果

1010 一元多项式求导

注意

  1. 指数为0的情况在不止有零多项式的情况下,是不需要输出的;

  2. 遇到指数为0的情况不一定停止输出/输入,可能有负指数项

    以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过 1000 的整数)   
    
  3. 输入时以回车为停止符的话,要在循环最后判断一次字符

代码

#include<iostream>
#include<vector>
using namespace std;
int main(){
    vector<int> ind;
    vector<int> apo;
    char ch;
    while(1){
        int index,apone;
        cin>>index>>apone;
        ind.push_back(index);
        apo.push_back(apone);
        if((ch = getchar()) == '\n' ) break;
    }
    int size=ind.size();
    for(int i=0;i<size;i++){
        ind[i]=ind[i]*apo[i];
        if(apo[i]!=0) apo[i]-=1;
    }
    for(int i=0;i<size;i++){
        if(ind[i]!=0){
            if(i!=0) cout<<' ';
            cout<<ind[i]<<' '<<apo[i];
        }
    }
    if(ind.size()==1&&ind[0]==0) cout<<ind[0]<<' '<<apo[0];
    return 0;
}

测试结果

1011 A+B和C

非常简单,直接判断就好了。
int型可以从-2147483648-2147483647。所以也没有溢出的问题

#include<iostream>
using namespace std;
int main(){
    int n;
    cin>>n;
    long long a[10];
    long long b[10];
    long long c[10];
    for(int i=0;i<n;i++) cin>>a[i]>>b[i]>>c[i];
    for(int i=0;i<n;i++){
        cout<<"Case #"<<i+1<<": ";
        if(a[i]+b[i]>c[i]) cout<<"true";
        else cout<<"false";
        if(i!=n-1) cout<<'\n';
    }
    return 0;
}

测试结果

1012 数字分类

读题

其实就是按照模5同余进行分类,得到的分类再进行一些基础的算术即可。
可以先输入以后再分类一次,也可以输入后直接对每个数字进行判断,也可以一边输入一边判断。影响不大。
看上去代码最简单的肯定是最后一种。

注意

  1. 判断是否输出N:
    如A2的结果可能会得到0,但是并不是没有结果。因此需要一个额外的signal进行标识

  2. 平均数计算:
    A4在进行最后的平均时,要注意先判断size是否为0,否则不能相除;
    相除的两个数均需为浮点型;

  3. 输出:
    cout输出固定小数点位数:

    cout << setiosflags(ios::fixed)<< setprecision(1)<<...
    

setprecision用于设定精度
需要加上头文件< iomanip >

代码

#include<iostream>
#include<vector>
#include<iomanip>
using namespace std;
int main(){
    int n,i=0;
    cin>>n;
    vector<int> init;
    for(;i<n;i++){
        int temp;
        cin>>temp;
        init.push_back(temp);
    }
    int a1,a2,a3,a5;
    float a4=0.0,a4count=0.0;
    a1=a2=a3=a5=0;
    int sig=1;
    int a2sig=0;
    for(i=0;i<n;i++){
        switch(init[i]%5){
            case 0:if(init[i]%2==0) {
                      a1+=init[i];break;
                   }
                   else break;
            case 1:a2+=init[i]*sig; sig*=-1; a2sig=1; break;
            case 2:a3++;break;
            case 3:a4+=init[i];a4count++;break;
            case 4:if(init[i]>a5) {
                      a5=init[i];break;
                   }
                   else break;
            default:break;
        }
    }
    a4=a4/a4count;
    if(a1==0) cout<<"N ";
    else cout<<a1<<' ';
    if(a2sig==0) cout<<"N ";//the result may be 0,but the output should be '0'. So we need another signal.
    else cout<<a2<<' ';
    if(a3==0) cout<<"N ";
    else cout<<a3<<' ';
    if(a4count==0) cout<<"N ";
    else cout << setiosflags(ios::fixed)<< setprecision(1)<<a4<<' ';
    if(a5==0) cout<<"N";
    else cout<<a5;
    return 0;
}

测试结果

1013 数素数

判断素数+计数

#include<iostream>
#include<vector>
using namespace std;
int main(){
    int m,n;
    cin>>m>>n;
    int i=2;
    int num=0;
    vector<int> res;
    while(num<n){
        int sig=0;
        for(int j=2;j<i/j+1;j++){//attention:j<j=i/j+1 减少了时间,不然无法通过
            if(i%j==0) {
                sig=1;
                break;
            }
            else continue;
        }
        if(sig==0) {
            num++;
            if(num>=m) res.push_back(i);
        }
        i++;
    }
    for(int i=0;i<(int)res.size();i++){
        cout<<res[i];
        if((i+1)%10==0) cout<<'\n';
        else if(i!=res.size()-1) cout<<' ';
    }
}

注意素数判断的时候要优化范围,否则会超时
测试结果

1014 福尔摩斯的约会

读题

给出四个字符串
提取一、二个字符串的第一个相同位置大写英文字母(A-G),第二个相同位置相同数字/大写英文字母(0-9,A-N)
提取三、四个字符串的第一个相同位置英文字母,根据位置判断精确时间

代码

#include<iostream>
#include<string>
using namespace std;
int main(){
    string s1,s2,s3,s4;
    cin>>s1>>s2>>s3>>s4;
    int i=0;
    int sig=0;
    for(;i<(s1.size()<s2.size()?s1.size():s2.size());i++){
        if(s1[i]==s2[i]){
            if((sig==0)&&s1[i]>='A'&&s1[i]<='G'){
                switch(s1[i]){
                    case 'A':cout<<"MON ";break;
                    case 'B':cout<<"TUE ";break;
                    case 'C':cout<<"WED ";break;
                    case 'D':cout<<"THU ";break;
                    case 'E':cout<<"FRI ";break;
                    case 'F':cout<<"SAT ";break;
                    case 'G':cout<<"SUN ";break;
                    default:break;
                }
                sig++;
            }
            else if((sig==1)&&((s1[i]>='A'&&s1[i]<='N')||(s1[i]>='0'&&s1[i]<='9'))){
                if(s1[i]>='0'&&s1[i]<='9') cout<<'0'<<s1[i]-'0'<<':';
                else cout<<s1[i]-'A'+10<<':';
                break;
            }
        }
    }
    for(i=0;i<(s3.size()<s4.size()?s3.size():s4.size());i++){
        if((s3[i]==s4[i])&&((s3[i]>='a'&&s3[i]<='z')||(s3[i]>='A'&&s3[i]<='Z'))){
            if(i>=10) cout<<i;
            else cout<<'0'<<i;
            break;
        }
    }
    return 0;
}

注意< > <= >=的使用

测试结果

1015 德才论

读题分析

八位准考证号——字符串/字符数组。考虑到排序的需要,且八位固定数字一定在int型表示范围内,我使用了int型(实际上是不符合现实意义的)

德分,才分有及格和优秀两条分数线,分成五种情况:
1.存在不及格:丢弃,达标数-1
2.都优秀:第一梯队输出
3.德分优秀,才分不优秀:第二梯队输出
4.都不优秀,德分>才分:第三梯队输出
5.其他

输出标准:梯队——总分——德分——准考证号

代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct Score{
   int id;
   int s1,s2;
 };
 bool compare(const Score& s,const Score& t){
    if(s.s1+s.s2!=t.s1+t.s2) return s.s1+s.s2>t.s1+t.s2;
    else if(s.s1!=t.s1) return s.s1>t.s1;
    else return s.id<t.id;
};

int main(){
    int n,l,h;
    cin>>n>>l>>h;
    int i=0;
    int count=n;
    vector<Score> data1,data2,data3,data4;
    for(;i<n;i++){
        Score temp;
        cin>>temp.id>>temp.s1>>temp.s2;
        if(temp.s1<l||temp.s2<l) count--;
        else if(temp.s1>=h&&temp.s2>=h) data1.push_back(temp);
        else if(temp.s1>=h&&temp.s2<h) data2.push_back(temp);
        else if(temp.s1>=temp.s2) data3.push_back(temp);
        else  data4.push_back(temp);
    }
    sort(data1.begin(),data1.end(),compare);
    sort(data2.begin(),data2.end(),compare);
    sort(data3.begin(),data3.end(),compare);
    sort(data4.begin(),data4.end(),compare);

    cout<<count;
    if(count!=0) cout<<'\n';
    for(i=0;i<(int)data1.size();i++) cout<<data1[i].id<<' '<<data1[i].s1<<' '<<data1[i].s2<<'\n';
    for(i=0;i<(int)data2.size();i++) cout<<data2[i].id<<' '<<data2[i].s1<<' '<<data2[i].s2<<'\n';
    for(i=0;i<(int)data3.size();i++) cout<<data3[i].id<<' '<<data3[i].s1<<' '<<data3[i].s2<<'\n';
    for(i=0;i<(int)data4.size();i++) {
        cout<<data4[i].id<<' '<<data4[i].s1<<' '<<data4[i].s2;
        if(i!=data4.size()-1) cout<<'\n';
    }
    return 0;
}

注意这里compare的写法
不能写三个compare然后依次使用,答案错误。因为它使用学号和德分排序是有前提的,

测试结果

1016 部分A+B

依次把给出的数字拆开(求余数——除10——……),和给出的数字对应,找出几个就得几位

#include<iostream>
using namespace std;
int main(){
    int a,b,da,db,pa,pb;
    cin>>a>>da>>b>>db;
    pa=pb=0;
    while(a!=0){
        int temp=a%10;
        a/=10;
        if(temp==da) pa=pa*10+da;
    }
    while(b!=0){
        int temp=b%10;
        b/=10;
        if(temp==db) pb=pb*10+db;
    }
    cout<<pa+pb;
    return 0;
}

没有坑,非常简单
测试结果

1017 A除以B

关于大整数

存储

结构体

使用数组存储每个数,按低位到高位存储
同时把长度也存储进结构中,得到

struct bignumber{
   int d[1000];
   int len;
}
初始化

一般一个普通定义的结构体,默认生成一个构造函数(不可见)。
如果需要自己手动提供初始化参数,就直接在结构体内部显式写出构造函数。
一个结构体可以定义多个构造函数,用于不同情况。
如:
为了无需初始化即可定义结构变量,写出默认构造函数:bignumber(){ };
只初始化len:bignumber(int _len){ len=_len;}

如果自己定义了新的构造函数,一定要把默认构造函数写上去,才能定义未初始化的变量

struct bignumber{
   int d[1000];
   int len;
   bign(){
      memset(d,0,sizeof(d)); //memset初始化函数,头文件<memory.h>
      len=0;
    }
}
读取

读入大整数时是以字符串形式读入,如“12345566778899”,为了在放入数组时是由低位到高位的,需要从字符串的最后一位向前读取,按顺序放在数组中。
这样在之后的运算等操作中,可以直接从低位向高位借位/进位/读取,方便很多

bignumber change(string str){
    bignumber a;
    a.len=str.size();
    for(int i=0;i<a.len;i++){
        a.d[i]=str[a.len-i-1]-'0';
    }
    return a;
}

四则运算

高精度加法

各位相加,向前进位,和低精度加法的运算规则相同

bignumber add(bignumber a,bignumber b){
   bignumber c;
   int carry=0;//进位
   for(int i=0;i<a.len || i<b.len;i++){
      int temp=a.d[i]+b.d[i]+carry;
      c.d[c.len++]=temp%10;
      carry=temp/10;
   }
   if(carry !=0){
      c.d[c.len++] =carry;//多的进位
   }
   return c;
}
高精度减法

对应位相减,不够则借位。和低精度减法规则相同。

bignumber sub(bignumber a,bignumber b){
   bignumber c;
   for(int i=0; i<a.len || i<b.len; i++){
      if(a.d[i]<b.d[i]){
         a.d[i+1]--;
         a.d[i]+=10;
      }
      c.d[c.len++]=a.d[i]-b.d[i];
    }
    while(c.len-1>=1&&c.d[c.len-1]==0) c.len--;
    return c;
}
高精度与低精度乘法

将低精度的整数看成一个整体,高精度每一位依次与其相乘,并与进位相加,个位数作为该位结果,其余高位部分全部进位
例如个位为7,35为int型,得到245,5保留,24全部进位

bignumber multi(bignumber a,int b){
   bignumber c;
   int carry=0;
   for(int i=0;i<a.len;i++){
      int temp=a.d[i]*b+carry;
      c.d[c.len++]=temp%10;
      carry=temp/10;
    }
    while(carry!=0){
       c.d[len++]=carry%10;
       carry/=10;//这里注意因为carry可能不止一位,所以要循环处理
    };
    return c;
}
高精度与低精度的除法

按照除法规则,每一步的被除数是这一位的数字+上一位的余数*10。除数是一个int型整数。
注意去掉多余的0

bignumber divide(bignumber a,int b,int& r){
    bignumber c;
    c.len=a.len;
    for(int i=a.len-1;i>=0;i--){
        r=r*10+a.d[i];
        if(r<b) c.d[i]=0;
        else{
            c.d[i]=r/b;
            r=r%b;
        }
    }
    while(c.len-1>=1 && c.d[c.len-1]==0) c.len--;
    return c;
}

这里余数采用引用的方式,这个函数同样可以用来获得余数r

代码

#include<iostream>
#include<string>
#include<memory.h>
using namespace std;
struct bign{
    int d[1010];
    int len;
    bign(){
        memset(d,0,sizeof(d));
        len=0;
    }
};
bign change(string str){
    bign a;
    a.len=str.size();
    for(int i=0;i<a.len;i++){
        a.d[i]=str[a.len-i-1]-'0';
    }
    return a;
}
bign divide(bign a,int b,int& r){
    bign c;
    c.len=a.len;
    for(int i=a.len-1;i>=0;i--){
        r=r*10+a.d[i];
        if(r<b) c.d[i]=0;
        else{
            c.d[i]=r/b;
            r=r%b;
        }
    }
    while(c.len-1>=1 && c.d[c.len-1]==0) c.len--;
    return c;
}
int main(){
    string s;
    int b,r=0;
    cin>>s;
    cin>>b;
    bign a=change(s);
    a=divide(a,b,r);
    for(int i=a.len-1;i>=0;i--) cout<<a.d[i];
    cout<<' '<<r;
    return 0;
}

测试结果

1018 锤子剪刀布

1.存储每次的结果
2.按顺序对比每次结果,获得输赢次数(甲赢次数=乙输次数,反之同理),记录每次赢的时候出的手势
3.比较手势赢的情况

#include<iostream>
#include<vector>
using namespace std;
int if_win_game(char x,char y){
    if(x==y) return 2;
    else if((x=='C'&&y=='J')||(x=='J'&&y=='B')||(x=='B'&&y=='C')) return 1;
    else return 0;
}
int print_max(int c,int b,int j){
    int max=j;
    if(c>=max) max=c;
    if(b>=max) max=b;
    if(max==b) cout<<'B';
    else if(max==c) cout<<'C';
    else cout<<'J';//attention! The order can't be reversed.
    return 0;
}
int main(){
    int n;
    cin>>n;
    vector<char> a,b;
    for(int i=0;i<n;i++){
        char jia,yi;
        cin>>jia;
        a.push_back(jia);
        cin>>yi;
        b.push_back(yi);
    }
    int awin,bwin,draw;
    int ac,ab,aj,bc,bb,bj;
    ac=ab=aj=bc=bb=bj=awin=bwin=draw=0;
    for(int i=0;i<n;i++){
        if(if_win_game(a[i],b[i])==1){
            awin++;
            if(a[i]=='C') ac++;
            else if(a[i]=='B') ab++;
            else aj++;
        } 
        else if(if_win_game(a[i],b[i])==0) {
            bwin++;
            if(b[i]=='C') bc++;
            else if(b[i]=='B') bb++;
            else bj++;
        }
        else draw++;
    }
    cout<<awin<<' '<<draw<<' '<<bwin<<'\n'<<bwin<<' '<<draw<<' '<<awin<<'\n';
    print_max(ac,ab,aj);
    cout<<' ';
    print_max(bc,bb,bj); 
    return 0;
}

测试结果

1019 数字黑洞

主要问题在排序
考虑到vector的sort函数可以轻松排序,使用了vector容器,创立一个新的函数每次用于排序

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int sort_up(int a){
    vector<int> res(4);
    for(int i=0;i<4;i++){
       res[i]=a%10;
       a/=10;
    }
    sort(res.begin(),res.end());
    int up=0;
    for(int i=3;i>=0;i--) up=up*10+res[i];
    return up;
}
int sort_down(int a){
     vector<int> res(4);
     for(int i=0;i<4;i++){
        res[i]=a%10;
        a/=10;
    }
    sort(res.begin(),res.end());
    int down=0;
    for(int i=0;i<4;i++) down=down*10+res[i];
    return down;
}
int main(){
    int a;
    cin>>a;
    while(1){
        int up=sort_up(a);
        int down=sort_down(a);
        int dif=up-down;
        printf("%04d - %04d = %04d",up,down,dif);//注意输出格式
        if(dif==0) return 0;
        else if(dif!=6174) {
            a=dif;
            cout<<'\n';
        }
        else break;
    }
    return 0;
}

测试结果

1020 月饼

给出月饼的总量、总价,给出最高的销售额。
把月饼按单价顺序降序排列,依次取即可
考虑到既要排序,每个月饼又有三个对应的值,可以新建一个结构

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct moon_cake{
    float store,price,retail;
};
bool compare(const moon_cake& a,const moon_cake& b){
    return a.retail>b.retail;
}
int main(){
    int n,d,i;
    cin>>n>>d;
    vector<moon_cake> a(1000);//输入的顺序不能直接push_back进一个完整的结构变量,所以先初始化
    for(i=0;i<n;i++) cin>>a[i].store;
    for(i=0;i<n;i++) cin>>a[i].price;
    for(i=0;i<n;i++) a[i].retail=a[i].price/a[i].store;
    sort(a.begin(),a.end(),compare);
    i=0;
    float res=0.00;
    while(d>0&&i<(int)a.size()){
        if(d>a[i].store) { 
            d-=a[i].store;
            res+=a[i].price;
        }
        else {
            res+=a[i].retail*d;
            break;
        }
        i++;
    }
    printf("%.2f",res);
    return 0;
}

测试结果

1021 个位数统计

依然是大整数的问题。之前已有描述。
除此以外,还要依次拆分每位的数,记录出现次数,并进行排序。这里我用了冒泡排序。

代码

#include<iostream>
#include<string>
#include<memory.h>
using namespace std;
struct bign{
    int d[1000];
    int len;
    bign(){
        memset(d,0,sizeof(d));
        len=0;
    }
};
bign change(string s){
    bign a;
    a.len=s.size();
    for(int i=0;i<a.len;i++) a.d[i]=s[a.len-i-1]-'0';
    return a;
}
int main(){
    string s;
    cin>>s;
    bign a=change(s);
    int num[1000][2]={0};
    int i,j,n=0;//n : record "num" length
    for(i=0;i<a.len;i++){
        for(j=0;j<n;j++){
            if(a.d[i]==num[j][0]){
                num[j][1]++;
                break;
            }
        }
        if(j==n) {
            num[n][0]=a.d[i];
            num[n++][1]++;
        }
    }
    for(i=0;i<n-1;i++){
        for(j=0;j<n-1;j++){
            if(num[j][0]>num[j+1][0]){
                int temp1=num[j][0];
                num[j][0]=num[j+1][0];
                num[j+1][0]=temp1;
                int temp2=num[j][1];
                num[j][1]=num[j+1][1];
                num[j+1][1]=temp2;
            }
        }
    }
    for(i=0;i<n;i++){
        cout<<num[i][0]<<':'<<num[i][1];
        if(i!=n) cout<<'\n';
    }
    return 0;
}

测试结果

关于排序

排序算法平均时间复杂度
冒泡排序O(n²)
选择排序O(n²)
插入排序O(n²)
希尔排序O(n1.5)
快速排序O(N*logN)
归并排序O(N*logN)
堆排序O(N*logN)
基数排序O(d(n+r))

具体算法待补充

实际运用中常使用C++的sort函数结合struct结构和compare谓词实现

1022 D进制的A+B

A+B的十进制结果C一定在int型表达范围内,但是转换成其他进制后如果还用int型输出,未必可以表达,因此要使用其他容器来存储结果
注意A、B都是非负整数,C有可能是0

#include<iostream>
using namespace std;
int main(){
    int a,b,d;
    cin>>a>>b>>d;
    int c=a+b;
    int res[31]={0};   //转换进制以后不一定在int范围内
    int len=0;
    if(d==10 || c==0){  //c=0的情况在下面是无法表达的
        cout<<c;
        return 0;
    }
    else{
        while(c!=0){
            res[len++]=c%d;
            c/=d;
        }
    }
    for(int i=len-1;i>=0;i--) cout<<res[i];
    return 0;
}

测试结果

1023 组个最小数

最小数一定是:高位小,低位大。
输入时直接按顺序先排好,再考虑前面的0即可
注意结果可能超出int型表示范围,要使用数组等其他容器

#include<iostream>
using namespace std;
int main(){
    int i=0;
    int res[50]={0}; //不超过50个,还是有可能超出的
    int len=0;
    for(;i<10;i++) {
        int num;
        cin>>num;  
        if(num==0) continue;
        else{
            int j=num;
            while(j>0){//每输入一个数,直接把对应的数放进去
                res[len++]=i;
                j--;
            }
        }
    }
    i=0;
    while(res[i]==0) i++;
    if(i!=0){
       res[0]=res[i];
       res[i]=0;//把除了0以外最小的数,和第一位的0交换位置
    }
    for(i=0;i<len;i++) cout<<res[i];
    return 0;
}

测试结果

1024 科学计数法

将读入的字符串拆分成:一位整数、多位小数、指数
然后按照指数的情况进行分类整合输出

#include<iostream>
#include<string>
#include<memory.h>
using namespace std;
struct bign{
    int d[9999];
    int len;
    bign(){
        memset(d,0,sizeof(d));
        len=0;
    }
};
int main(){
    string s;
    cin>>s;
    char signal=s[0];  //总体符号
    int a=s[1]-'0';//整数只有一位
    int i=3;
    bign sml;//小数部分可能很长
    while(1){
        if(s[i]=='E') break;
        sml.d[i-3]=s[i]-'0';
        sml.len++;
        i++;
    }
    char expsig=s[i+1];//指数部分的符号
    int exp=0;
    i+=2;
    while(i<s.size()){
        exp=exp*10+(s[i]-'0');
        i++;
    }
 i=0;
 if(expsig=='-'){
  exp*=-1;//指数为负
  i+=exp;
        if(signal=='-') cout<<'-';
  cout<<"0.";
  for(;i<-1;i++) cout<<'0';
  cout<<a;
        i++;
  for(;i<sml.len;i++) cout<<sml.d[i];
 }
 else{
        if(signal=='-') cout<<'-';
  cout<<a;
  for(;i<exp;i++) cout<<sml.d[i];
  if(i<sml.len){
   cout<<'.';
      for(;i<sml.len;i++) cout<<sml.d[i];
  }
 }
    return 0;
}

测试结果
注意这里存储小数的数组一定要设的足够大

1025 反转链表

相比平常的反转链表,这里是以整数为虚拟地址的特殊情况。
可以设定一个足够大的数组,使得索引=地址,方便查找。如果使用顺序存储,每次查找都需要一个循环。
然后使用辅助数组存储链表的地址顺序。翻转时直接对数组进行翻转,变换读取顺序即可
这里借鉴了数据结构课程中对数组上的特殊链表的讲解。

#include<iostream>
using namespace std;
typedef struct node
{ 
 int data;
 int next;
 node(){
  data=next=0;
 }
};
node input[100000];
int chain[100000]={0};
int main( )
{
 int first,n,k,i;
 cin>>first>>n>>k;
 for(i=0;i<n;i++){
  int temp;
  cin>>temp;
  cin>>input[temp].data>>input[temp].next;
 }
 int index=0;
  for(;first!=-1;index++){//这里的条件不能换成index<n
  chain[index]=first;
  first=input[first].next;
 }
 for(int i=0;i<(index)/k;i++)
 {
  int left=i*k,right=(i+1)*k-1;
  while(left<right){
     int temp=chain[left];
     chain[left]=chain[right];
     chain[right]=temp;
     left++,right--;
     }
 }
  printf("%05d %d",chain[0],input[chain[0]].data);
 for(int i=1;i<index;i++)
  printf(" %05d\n%05d %d",chain[i],chain[i],input[chain[i]].data);
 printf(" -1\n")return 0;
}

测试结果

1026 写程序运行时间

直接相减然后除以100(注意是浮点型结果)然后四舍五入
进行时间换算即可
注意输出格式
四舍五入:floor()和ceil()函数,头文件<math.h>

#include<iostream>
#include<math.h>
#define CLK_TCK 100
using namespace std;
int main(){
    int c1,c2;
    cin>>c1>>c2;
    float tm=(float)(c2-c1)/(float)CLK_TCK;
    int clock;
    if(ceil(tm)-tm>0.5) clock=floor(tm);
    else clock=ceil(tm);
    int h=clock/3600;
    clock=clock%3600;
    int m=clock/60;
    clock=clock%60;
    int s=clock;
    printf("%02d:%02d:%02d",h,m,s);
    return 0;
 }

测试结果

1027 打印沙漏

代码

//1,7,17,31...sum
//1,3,5,7... maximum
//0,1,2,3... signal
#include<iostream>
#include<string>
using namespace std;
int sum_n(int n){
    return n*(2*n+4)+1;
}
int if_sym(int n){    
    int i=0;
    if(n==0) return 0;
    while(1){
        if(n>=sum_n(i)&&n<sum_n(i+1)) return i;
        else i++;
    }
}
int main(){
    int sum,i;
    char x;
    cin>>sum>>x;
    int n=if_sym(sum);
    int max=2*n+1;
        i=0;
    int flag=0;
    while(1){
        for(int j=1;j<=max-i;j++) {
            if(j>i) cout<<x;
            else cout<<' ';
        }
        cout<<'\n';
        if(i==0) {
            if(!flag) flag=1;
            else break;
        }
        if(i==(max-1)/2) flag=2;
        if(flag==1) i++;
        else if(flag==2) {
            if(i!=0) i--;
            else break;
        }
    }
    cout<<sum-sum_n(n)<<'\n';
    return 0;
}

测试结果

注意&知识点

  1. 输出时只要输出左边的空格就可以了,右边将符号输完后就可以直接回车了(再输出空格判定为格式错误)
  2. 注意sum=1的情况。这里我没有拆成两个循环,而是直接用flag判定i的变化情况,然后在一个while里完成。sum=1时注意判定
  3. 字符串连接:循环 和 “+”运算符
    strcpy不必在C++中使用。C中的str函数在C++中要加上< cstring >头文件

1028 人口普查

注意

  1. 主要是对日期的判断。注意没有一个日期符合条件的情况!
    不是说一个日期都没有“输入”,而是说没有一个日期“符合条件

  2. 在输入年月日的时候,scanf可以直接按照格式将其转化为数字
    如果使用cin,要经历从字符串到整数的变化过程。

  3. 在给max和min赋值时,也不能简单地使用i=0,将第一个赋值给他们。因为第一个可能是不符合条件的
    在设定结构的时候就设定初值,就可以比较这个来判断是否已经赋给max、min合理的值

代码

#include<iostream>
#include<string>
using namespace std;
struct people{
    string name;
    int year,month,day;
    people(){
        name="";//空字符串
        year=month=day=0;
    }
};
int check(people a){
    if(a.year<1814) return 1;
    if(a.year==1814){
        if(a.month<9) return 1;
        if(a.month==9 && a.day<6) return 1;
        return 0;
    }
    if(a.year>2014) return 1;
    if(a.year==2014){
        if(a.month>9) return 1;
        if(a.month==9 && a.day>6) return 1;
    }
    return 0;
}
int comp(people a,people b){
    if(a.year>b.year) return 1;
    if(a.year==b.year){
        if(a.month>b.month) return 1;
        if(a.month==b.month && a.day>b.day) return 1;
    }
    return 0;
}
int main(){
    int n;
    cin>>n;
    int stdrd=n;
    people max,min;
    for(int i=0;i<n;i++) {
        people temp;
        cin>>temp.name;
        scanf("%d/%d/%d",&temp.year,&temp.month,&temp.day);
        if(check(temp)) stdrd--;
        else {
            if(max.year==0) {//判断是否已经赋值了
                max=min=temp;
                continue;
            }
            if(comp(max,temp)) max=temp;
            if(comp(temp,min)) min=temp;
        }
    }
    if(stdrd==0) cout<<"0";//没有符合条件的情况
    else cout<<stdrd<<' '<<max.name<<' '<<min.name;
 system("pause");
    return 0;
}

测试结果

1029 旧键盘

比对两个字符串即可。
注意

  1. 循环条件一定要是较长的字符串,即“应该输入的字符串
  2. 只需要一层循环,调整每种情况后的序号即可
  3. 可以使用数组标记每个字符是否存储过:只有0-9,a-z,A-Z,_这几种情况。较为简洁
    之前我使用循环判断是否已经放入容器,但是始终有一个答案错误,而且显得冗长
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int sig[95]={0};
int main(){
    string s1,s2;
    cin>>s1>>s2;
    int i,j;
    vector<char> wrong;
    i=j=0;
    while(s1[i]){
        if(s1[i]==s2[j]) {
            i++;
            j++;
        }
        else {
            int temp;
            if(s1[i]>='a' && s1[i]<='z') temp=s1[i]+'A'-'a';
            else temp=s1[i];
            if(!sig[temp]){
                sig[temp]=1;
                wrong.push_back(temp);
            }              
            i++;
        }
    }
    for(i=0;i<(int)wrong.size();i++) cout<<wrong[i];
    return 0;
}

测试结果

1030 完美数列

读题分析

要求找出尽可能多满足M<=mp的数列

  1. 这无法从单向判断,例如:

    1,20,30,40,50,60,70,80,130

    p=4
    最长的是从20开始到80
    所以必须从小开始逐一判断,直到最大的数<=mp才能停止

  2. 为了缩短时间,判断的时候就直接代入max判断当前序列+max的结果是否还在完美序列内
    如果还在,说明比现有的max还长,继续判断;如果不在,那么没有继续判断的必要

  3. 需要先排序,方便判断

代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
    int n,p,i,j;
    cin>>n>>p;
    vector<long> num;
    for(i=0;i<n;i++){
        long int temp;
        cin>>temp;
        num.push_back(temp);
    }
    sort(num.begin(),num.end());
    int max=0;
    for(i=0;i<n;i++){
        long int mp=num[i]*p;
        for(j=i+max;j<n;j++){
            if(num[j]>mp) break;
            else {
                if(j-i+1>max)  max=j-i+1;
            }
        }
    }
    cout<<max;
    return 0;
}

注意:一定要使用long int型表达数列中的数,否则无法通过最后一条测试

测试结果

1031 查验身份证

输入字符串后:

  1. 判断每个字符是否为数字:
    是:加入加权求和
    不是:不合格标志
  2. 取模对应校验码:
    正确:检验下一个字符串
    错误:不合格标志

注意此题不能一边输入一边输出,会导致格式不正确

#include<iostream>
#include<string>
using namespace std;
int weight[17]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
char zm[11]={'1','0','X','9','8','7','6','5','4','3','2'};
int main(){
    int n,i,if_passed=0;
    cin>>n;
    string s[100];
    int flag[100]={0};//if all numbers(0-16)
    for(i=0;i<n;i++) {
        cin>>s[i]; 
        int z=0;
        for(int j=0;j<17;j++) {
            if(s[i][j]>='0'&&s[i][j]<='9') 
                z+=(s[i][j]-'0')*weight[j];
            else {
                if_passed=1;
                flag[i]=1;
                break;
            }
        }
        if(!flag[i]){
            z%=11;
            if(s[i][17]==zm[z]) continue;
            else{
                flag[i]=1;
                if_passed=1;
            }
        }
    }
    if(!if_passed) cout<<"All passed";
    else{
        for(i=0;i<n;i++){
            if(flag[i]) cout<<s[i]<<'\n';
        }
    }
    return 0;
}

测试结果

1032 挖掘机技术哪家强

由于学校都是编号,在输入的时候就可以直接把对应学校的成绩累加起来了。

唯一需要注意的是,可以在输入的时候也把最大值的判断加进去
如果在之后再另开循环的话,循环截止条件是比较麻烦的,无论是需要新增学校数这个变量来判断,还是根据数组当前的数据(也有可能这个学校有人考了但是考了零分),都增加了不必要的开销

#include<iostream>
using namespace std;
int sum_sco[100005]={0};
int main(){
    int n,i;
    cin>>n;
    int max=1;
    for(i=0;i<n;i++){
        int school,score;
        cin>>school>>score;
        sum_sco[school]+=score;
        if(sum_sco[school]>sum_sco[max]) max=school;//虽然增加了一些不必要的判断,但是整体上是优化了的
    }
    cout<<max<<' '<<sum_sco[max];
    return 0;
}

测试结果

1033 旧键盘打字

问题

和之前的旧键盘那题类似。
我遇到的奇怪bug是当我先使用string将两个字符串存储,再用for循环处理的时候会有答案错误。
而一边记录字符一边处理,用回车查看是否停止循环的方式,就全部正确。(第二个可以继续cin>>s,使用for循环,也是正确的)
不是很清楚原理,不知道有没有大佬知道是为什么。

答案错误的第一个循环是用:

string wrong,input;
cin>>wrong>>input;
for(int i=0;i<(int)wrong.size();i++){
   //将下方正确答案的c替换成wrong[i],其余不变
   //......
   }
   

代码

#include<iostream>
#include<string>
using namespace std;
int sig[125]={0};
int main(){
    char c;
    int i;
    while((c=getchar())!='\n') {
        sig[c]=1;
        if(c>='A'&& c<='Z') sig[c+'a'-'A']=1;//小写也打不出来
    }
    while((c=getchar())!='\n'){
        if(sig[c]||(sig[43] && (c>='A' && c<='Z'))) continue;
        else cout<<c;
    }
    cout<<'\n';
    return 0;
}

测试结果

1034 有理数四则运算

读题&分析

  1. 输入的样例一定是a/b的形式,没有整数部分:只要在最后输出的时候输出整数部分就可以了
  2. 化简要考虑:提取整数;负号位置;上下约分;/0情况
  3. 操作顺序:获取两个分数——计算——将结果和两个数标准化——输出

代码

#include<iostream>
#include<cmath>
using namespace std;
struct frac{
    long long int itg;
    long long int num;
    unsigned long long den;
    frac(){
        itg=num=den=0;//未赋值的时候分子分母均为0
    }
};

long long measure(long long x, long long y){
    long long z=y;
    while(x%y!=0){
        z=x%y;
        x=y;
        y=z;
    }
    return z;
}

frac add(frac a,frac b){
    frac c;
    c.den=a.den*b.den;
    c.num=a.num*b.den+b.num*a.den;
    return c;
}

frac sub(frac a,frac b){
    frac c;
    c.den=a.den*b.den;
    c.num=a.num*b.den-b.num*a.den;
    return c;
}

frac mul(frac a,frac b){
    frac c;
    c.den=a.den*b.den;
    c.num=a.num*b.num;
    return c;
}

frac div(frac a,frac b){
    frac c;
    c.den=a.den*abs(b.num);
    c.num=a.num*b.den;
 if(b.num<0) c.num*=-1;
    return c;
}

void stad(frac& x){
    if(x.den==0 || x.num==0) 
        return;
 int sig=0;
 if(x.num<0)sig=1;
 x.num=abs(x.num);
 int mea=measure(x.num,x.den);
    x.num/=mea;
    x.den/=mea;//上下约分
    x.itg=x.num/x.den;//整数部分:如果没有,itg=0
    x.num%=x.den;//小数部分:如果没有了,num=0,den不变

    if(x.itg){
        if(sig) x.itg*=-1;
    }
    else if(!x.itg && x.num) {
        if(sig) x.num*=-1;
    }
}

void print(frac y){
 if(y.den==0) {
  cout<<"Inf";
  return;
 }
 else if(!y.itg && !y.num) {
  cout<<'0';
  return;
 }
 int sig=0;
 if(y.itg<0 || y.num<0) sig=1;
 if(y.itg && y.num){
  if(sig) cout<<'('<<y.itg<<' '<<y.num<<'/'<<y.den<<')';
  else cout<<y.itg<<' '<<y.num<<'/'<<y.den;
 }
  else if(y.itg && !y.num){
  if(sig) cout<<'('<<y.itg<<')';
  else cout<<y.itg;
 }
 else if(!y.itg){
  if(sig) cout<<'('<<y.num<<'/'<<y.den<<')';
  else cout<<y.num<<'/'<<y.den;
 }
}

int main(){
    frac a,b;
    scanf("%lld/%lld %lld/%lld",&a.num,&a.den,&b.num,&b.den);
    frac c=add(a,b);
    frac d=sub(a,b);
    frac e=mul(a,b);
    frac f=div(a,b);
    stad(a);
    stad(b);
    stad(c);
    stad(d);
    stad(e);
    stad(f);
    print(a);
    cout<<" + ";
    print(b);
    cout<<" = ";
    print(c);
    cout<<'\n';
    print(a);
    cout<<" - ";
    print(b);
    cout<<" = ";
    print(d);
    cout<<'\n';
    print(a);
    cout<<" * ";
    print(b);
    cout<<" = ";
    print(e);
    cout<<'\n';
    print(a);
    cout<<" / ";
    print(b);
    cout<<" = ";
    print(f);
    cout<<'\n';
    return 0;
}
 

测试结果

其他

为了方便我使用了一个新的结构。也可以直接使用二维数组来存储,在最后输出的时候再考虑整数的问题

因为分母是不可能有负数的,因此我使用了unsigned型。这会导致当分子是负数的时候,直接相除得到的整数部分会退化成无符号类型,因此需要额外处理。
也可以直接全部设成有符号类型,对分母是负数的情况另外判断

一定要使用双精度型!分母相乘的时候很有可能会超出范围。

1036 跟奥巴马一起编程

普通的图形输出题

代码

#include<iostream>
#include<string>
#include<math.h>
using namespace std;
int main(){
    int n,i;
    char c;
    cin>>n>>c;
    int x=(ceil((float)n/2.0)-(float)n/2.0>(float)n/2.0-floor((float)n/2.0)?floor((float)n/2.0):ceil((float)n/2.0));
    for(i=0;i<x;i++){
        cout<<c;
        string s;
        if(i==0 || i==x-1) s.assign(n-2,c);
        else s.assign(n-2,' ');
        cout<<s<<c<<'\n';
    }
    return 0;
}

测试结果

C++中string相关总结

头文件: #include < string >

构造函数

string str;        //空字符串 
string str("ABC")  //str="ABC"
string str("ABC",n)  // 将"ABC"存到str里,最多存储前n个字节 
string s("ABC",i,n)   //将"ABC"的i位置,作为字符串开头,存到str里.且最多存储n个字节.    
string s(n, 'A')  //n个'A'到str里:常用于图形输出

成员函数

性质&添加删除
str1.assign("ABC")//清空string串,然后设置string串为"ABC"
str1.length()//获取字符串长度
str1.size();            //获取字符串数量
str1.length();
str1.capacity();          //获取容量
str1.resize(10);          //表示设置当前string里的串大小,若设置大小大于当前串长度,则用字符\0来填充多余的
str1.resize(10,char c);    //设置串大小,若设置大小大于当前串长度,则用字符c来填充多余的 
str1.reserve(10);          //设置string里的串容量,不会填充数据
str1.swap(str2);           //替换str1 和 str2 的字符串 
str1.puch_back('A');     //在str1末尾添加一个'A'字符,参数是字符形式  
str1.append("ABC");       //在str1末尾添加一个"ABC"字符串,参数是字符串形式 
str1.insert(2,"ABC");     //在str1的下标为2的位置,插入"ABC" 
str1.erase(2);            //删除从下标为2的位置开始的内容
str1.erase(2,1);           //从下标为2的位置删除1个
str1.clear();          
str1.replace(2,4, "ABCD"); //从下标为2的位置,替换4个字节,为"ABCD" 
str1.empty();            //判断为空, 为空返回true
赋值函数
str1.assign("HELLO");       //str1="HELLO"
str1.assign("HELLO", 4);    //str1="HELL" ,只保留4个字符
str1.assign("HELLO", 2, 3); //str1="LLO" ,从位置2开始,只保留3个字符
str1.assign(5, 'c');        //str1="CCCCC",常用于图形输出题
char*与string转换
const char* c_str();   //返回一个新的常量C字符串, 内容与本string串相同
查找
string str("ABCDEFGABCD");   //例
/*查找成功返回位置,查找失败,则返回-1*/
/*find():从头查找某个字符串*/

str.find('A');              //查找"A"
str.find("AB");             //查找"AB"
str.find("BC",1);           //从位置1处,查找"BC"
str.find("CDEfg",1,3);      //从位置1处,查找"CDEfg"的前3个字符

 /*rfind():反向(reverse)查找,从末尾处开始,向前查找*/ str.rfind("CD");           //从位置10开始向前查找
str.rfind("CD",5);         //从位置5开始向前查找,n=2 
str.rfind("CDEfg",5,3);    //从位置5处,查找"CEDfg"的前3个字符     

/* find_first_of ():查找str里是否包含有子串中任何一个字符*/
str.find_first_of("abcDefg");     //返回str中第一个遇到的"D"的位置
str.find_first_of("abcDefg",1);   //从位置1处,查找"abcDefg"中的字符
str.find_first_of("abcDefg",1,4); //从位置1处,查找"abcDefg"的前4个字符

/* find_last_of ():末尾查找, 从末尾处开始,向前查找是否包含有子串中任何一个字符*/ 
str.find_last_of("abcDefg");      
str.find_last_of("abcDefg",5,4);  

/* find_first_not_of ():匹配子串字符,若存在子串中没有的字符,则返回str处的位置,全相等返回-1*/
//子串相当于总表,字符串相当于一个特例,查找超出表内容的字符//
str.find_first_not_of("ABC");    //由于str位置3'D',在子串里没有,所以返回3
str.find_first_not_of("aABDC");  //由于str位置4'E',在子串里没有,所以返回4
str.find_first_not_of("aBDC");   //由于str位置0'A',在子串里没有,所以返回0

/* find_last_not_of ():反向匹配*/ str.find_last_not_of("aBDC");  //由于str位置7'A',在子串里没有,所以返回7
拷贝
str1.substr(2);           //提取子串,提取出str1的下标为2到末尾 
str1.substr(2,3);         //提取子串,从 str1的下标为2开始,提取3个字节
const char *s1= str.data();//将string类转为字符串数组,返回给s1
char *s=new char[10]; str.copy(s,count,pos);    //将str里的pos位置开始,拷贝count个字符,存到s里.

1037 在霍格沃兹找零钱

全部转化成最小单位然后相减,再化为标准形式即可

#include<iostream>
using namespace std;
int main(){
    int pgal,psick,pknt;
    int agal,asick,aknt;
    scanf("%d.%d.%d %d.%d.%d",&pgal,&psick,&pknt,&agal,&asick,&aknt);
    int ret=17*29*agal+29*asick+aknt-(17*29*pgal+29*psick+pknt);
    int sig=0;
    if(ret<0) {
        sig=1;
        ret*=-1;
    }
    int rgal=ret/493;
    ret%=493;
    int rsick=ret/29;
    ret%=29;
    if(sig) cout<<'-';
    cout<<rgal<<'.'<<rsick<<'.'<<ret;
    return 0;
}

测试结果

1038 统计同成绩学生

一共只有百分制。使用一个数组,边输入边记录每个分数的学生人数即可。
注意
C++很可能也无法通过最后一条测试的时间要求。将转化成代码基本没有区别的C即可
或者使用scanf和printf

C版本:

#include<stdio.h>  //C++:#include<iostream>
#include<stdlib.h>//C++:using namespace std;
int score[101]={0};
int main(){
    int n,temp;
    scanf("%d",&n);
    while(n--){
        scanf("%d",&temp);
        score[temp]++;
    }
    scanf("%d",&n);
    while(n--){
        scanf("%d",&temp);
        printf("%d",score[temp]);
        if(n) printf(" ");
    }
    return 0;
}

使用cin和cout会超时。即使C++也只能用scanf 和printf
测试结果

1039 到底买不买

设定一个数组,对给出的串子进行计数。
输入想要的颜色时,对对应的数组位置减数。

#include<iostream>
#include<string>
using namespace std;
int main(){
    int give[130]={0};
    int dif=0;
    char c;
    while((c=getchar())!='\n')
        give[c]++;
    while((c=getchar())!='\n'){
        give[c]--;
        if(give[c]<0) dif++;//一定不能减give[c]!会重复叠加
    }
    if(dif==0){//该有的都有
        for(int i=0;i<130;i++)
            if(give[i]>0) dif+=give[i];
        cout<<"Yes "<<dif;
    }
    else cout<<"No "<<dif;
    return 0;
}

测试结果

1040 有几个PAT

读题可知,要计算所有的PAT,即计算所有P位置<A位置<T位置的组合
所以计算每个A前面的P个数和后面的T个数即可

#include<iostream>
#include<string>
using namespace std;
int pA[100005]={0};
int At[100005]={0};
int main(){
    string s;
    cin>>s;
    int p=0,t=0,last=0,i=0;
    for(;i<(int)s.size();i++){
        if(s[i]=='P') p++;
        else if(s[i]=='A') pA[i]=p;
    }
    for(i=s.size()-1;i>=0;i--){
        if(s[i]=='T') t++;
        else if(s[i]=='A') At[i]=t;
    }
    long long sum=0;
    for(i=0;i<100005;i++) sum+=pA[i]*At[i];
    cout<<sum%1000000007;
    return 0;
}

测试结果

1041 考试座位号

也很简单,试机座位号是按顺序从1到N,每个准考证号存储在对应序号的数组里,另设一个数组存储对应的考试座位号。查询时直接查询试机座位号,即数组序号

#include<iostream>
#include<string>
using namespace std;
int main(){
    int N;
    cin>>N;
    string lis1[1005];
    int lis2[1005]={0};
    for(int i=0;i<N;i++){
        string temp;
        cin>>temp;
        int j,k;
        cin>>j>>k;
        lis1[j]=temp;
        lis2[j]=k;
    }
    int M;
    cin>>M;
    for(int i=0;i<M;i++) {
        int s;
        cin>>s;
        cout<<lis1[s]<<' '<<lis2[s];
        if(i!=M) cout<<'\n';
    }
    return 0;
}

测试结果

1042 字符统计

输入时直接计数。同时可以每次都判断一下最大值,简化代码。
注意这里最大值只考虑英文字母,但是字符串里会有其他字符。

#include<iostream>
#include<string>
using namespace std;
int sum[130]={0};
int main(){
    char ch;
    int max=97;//'a'
    while((ch=getchar())!='\n'){
        if(ch>='A'&&ch<='Z') ch+='a'-'A';//小写
        sum[ch]++;
        if((ch>='a'&&ch<='z')&&(sum[ch]>sum[max] || (sum[ch]==sum[max] && ch<max))) max=ch;
    }//英文字母:相等时取字母序小的那个
    cout<<(char)max<<' '<<sum[max];
    return 0;
}

测试结果

1043 输出PATest

就是计数有多少对应字母,按顺序输出即可

#include<iostream>
using namespace std;
int main(){
    char ch;
    int sum[6]={0};
    while((ch=getchar())!='\n'){
        switch(ch){
            case 'P':sum[0]++;break;
            case 'A':sum[1]++;break;
            case 'T':sum[2]++;break;
            case 'e':sum[3]++;break;
            case 's':sum[4]++;break;
            case 't':sum[5]++;break;
            default:break;
        }
            }
    while(sum[0]||sum[1]||sum[2]||sum[3]||sum[4]||sum[5]){
        if(sum[0]){
            cout<<'P';
            sum[0]--;
        }
        if(sum[1]){
            cout<<'A';
            sum[1]--;
        }
        if(sum[2]){
            cout<<'T';
            sum[2]--;
        }
        if(sum[3]){
            cout<<'e';
            sum[3]--;
        }
        if(sum[4]){
            cout<<'s';
            sum[4]--;
        }
        if(sum[5]){
            cout<<'t';
            sum[5]--;
        }
    }
    return 0;
}

测试结果

1044 火星数字

数制转换。
注意13、26、39这类数字,火星数字表示的时候,个位不需要0,直接用进位数字表示即可

#include<iostream>
#include<string>
using namespace std;
string num[26]={"tret","jan","feb","mar","apr","may","jun","jly","aug","sep","oct","nov","dec","tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mer","jou"};
int change(string s){
    int a=0;
    for(int i=0;i<(int)s.size();i++) a=a*10+s[i]-'0';
    return a;
}

void ear_mar(int a){
    int t=a/13;
    int l=a%13;
    if(!t) cout<<num[l];
    else if(!l) cout<<num[t+12];
    else cout<<num[t+12]<<' '<<num[l];
}

string cut(string& s){
    int i=0;
    while(s[i]!=' ') i++;
    string s2=s.substr(i+1);
    s=s.substr(0,i);
    return s2;
}

void mar_ear(string s){
    if(s.size()<5) {
        for(int j=0;j<26;j++){
            if(s==num[j]){
                if(j>=13) cout<<(j-12)*13;
                else cout<<j;
                break;
            }
        }
    }
    else{
        string temp=cut(s);
        int res=0;
        for(int j=0;j<26;j++){
            if(s==num[j]) {
                res+=(j-12)*13;
                break;
            }
            if(temp==num[j]) res+=j;
        }
        cout<<res;
    }
}

int main(){
    int n;
    cin>>n;
    string s[100];
    getchar();
    for(int i=0;i<n;i++){
        char ch;
        while((ch=getchar())!='\n') s[i].push_back(ch);
    }
    for(int i=0;i<n;i++){
        if(s[i][0]>='0' && s[i][0]<='9') {
            int temp=change(s[i]);
            ear_mar(temp);
        }
        else mar_ear(s[i]);
        if(i!=n-1) cout<<'\n';
    }
    return 0;
}

测试结果
也可以使用char类型,这样就能方便地使用sscanf、sprintf进行类型转换。

1045 快速排序

两次循环比较两边的数即可
有一个坑是如果答案是0,要回车两次

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int lis[100005]={0};
int sig[100005]={0};
int main(){
    int n,i;
    cin>>n;
    for(i=0;i<n;i++) cin>>lis[i];
    int min_right=lis[n-1];
    for(i=n-2;i>=0;i--){
        if(lis[i+1]<min_right) min_right=lis[i+1];
        if(lis[i]>min_right) sig[i]=1;
    }
    int max_left=lis[0];
    vector<int> result;
    if(!sig[0]) result.push_back(lis[0]);
    for(i=1;i<n;i++){
        if(lis[i-1]>max_left) max_left=lis[i-1];
        if(lis[i]<max_left) sig[i]=1;
        if(!sig[i]) result.push_back(lis[i]);
    }
    cout<<result.size()<<'\n';
    sort(result.begin(),result.end());
    for(i=0;i<(int)result.size();i++) {
        cout<<result[i];
        if(i!=result.size()-1) cout<<' ';
        else cout<<'\n';
    }
    if(!result.size()) cout<<'\n';
    return 0;
}

测试结果

1046 划拳

非常简单,条件判断一下就可以了

#include<iostream>
using namespace std;
int main(){
    int n;
    cin>>n;
    int ahan,ahua,bhan,bhua;
    int jia=0,yi=0;
    for(int i=0;i<n;i++) {
        cin>>ahan>>ahua>>bhan>>bhua;
        int c=ahan+bhan;
        if(ahua==c && bhua!=c) yi++;
        else if(bhua==c && ahua!=c) jia++;
        else continue;
    }
    cout<<jia<<' '<<yi;
    return 0;
}

测试结果

1047 编程团体赛

利用数组序号直接累加对应队伍的分数

#include<iostream>
using namespace std;
int main(){
    int n;
    cin>>n;
    int score[10005]={0};
    int max=0;
    for(int i=0;i<n;i++){
        int sig,j,sco;
        scanf("%d-%d %d",&sig,&j,&sco);
        score[sig]+=sco;
        if(score[sig]>score[max]) max=sig;
    }
    cout<<max<<' '<<score[max];
    return 0;
}

测试结果

1048 数字加密

考虑到是从个位开始对齐计算的,而且读入的时候最好一位一位读入,所以设计读入char字符,转换成整数后放入

#include<iostream>
#include<stack>
#include<string>
using namespace std;
int main(){
    char c;
    stack<int> a,b;
    while((c=getchar())!=' ') a.push(c-'0');
    while((c=getchar())!='\n') b.push(c-'0');
    int sig=1;
    stack<char> res;
    while((!a.empty()) || (!b.empty())){
        int temp;
        if(sig%2){
            if(a.empty()) { 
                temp=b.top()%13; 
                b.pop();
            }
            else if(b.empty()) {
                temp=a.top()%13;
                a.pop();
            }
                        else {
                temp=(a.top()+b.top())%13;
                a.pop();b.pop();
            }
            switch(temp){
                case 10:c='J';break; 
                case 11:c='Q';break;
                case 12:c='K';break;
                default:c=temp+'0';break;
            }
        }
        else{
            if(a.empty()) {
                temp=b.top();
                b.pop();
            }
            else if(b.empty()) {
                temp=(a.top()==0)?0:(10-a.top());
                a.pop();
            }
            else {
                temp=b.top()-a.top()+(b.top()<a.top()?10:0);
                a.pop();b.pop();
            }
            c=temp+'0';
        }
        res.push(c);
        sig++;
    }
    while(!res.empty()){
        cout<<res.top();
        res.pop();
    }
    return 0;
}

注意A比B长的情况,不能直接放入,偶数位还是要计算,而且如果为0,不能直接加10
测试结果

1049 数列的片段和

挨个加是会超出时间限制的。观察规律可以发现,每个数在每一轮中加的次数都是n-i(如观察2,从1,1+2,1+2+3,1+2+3+4,……,2加的次数取决于一共多少个数n,去掉开始的1,即没到2之前的数的个数1),加的轮数是i+1轮,所以一共是(n-i)(i+1)次

有个非常重要,总是过不去的问题是,double类型有52位尾数,单用double类型是过不去测试点3的
需要用long long型先转一次,输出的时候再转回去
而且转的过程中,求每个数的总结果时,一定要把(long long)(temp*1000)放在前面

#include<iostream>
using namespace std;
int main(){
    int n;
    long long sum=0;
    double temp;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>temp;
        sum+=(long long)(temp*1000)*(n-i)*(i+1);
    } 
    printf("%.02lf\n",sum/1000.0);
    return 0;
}

测试结果

1050 螺旋矩阵

读题

  1. “非递增顺序”:需要排序
  2. 螺旋方向:非正常方向。输出的时候要按顺序输出,考虑先按照螺旋顺序放入数组中。矩阵需要二维数组。
  3. N=m×n,m≥n:计算m和n,考虑平方根函数、质数的问题
  4. N没有给范围:动态二维数组的申请

动态二维数组

需要两次申请

  1. malloc:
int **matrix=(int**)malloc(10*sizeof(int*));
for(i=0;i<10;i++)		    
    matrix[i]=(int*)malloc(10*sizeof(int));

malloc函数不负责初始化

  1. calloc:
int **matrix=(int**)calloc(10,sizeof(int*));
for(i=0;i<10;i++)  
    matrix[i]=(int*)calloc(10,sizeof(int));

calloc函数负责初始化

  1. new:
int **matrix=new int*[10];
for(i=0;i<10;i++)  
    matrix[i]=new int[10];

在本题中使用new会导致内存超限

使用malloc或calloc后记得使用free函数释放
使用new函数后记得使用delete释放

代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
using namespace std;
int matrix(int& n){
    int m;
    int c=floor(sqrt(float(n)));
    if(!(n%c)) {
        m=n/c;
        n=c;
    }
    else{
         for(;c>0;c--){
            if(!(n%c)){
                m=n/c;
                n=c;
                break;
            }
        }
    }
    return m;
}

bool compare(int& a,int& b){
 return a>=b;
}

int main(){
    int n,i,j,k;
    cin>>n;
    vector<int> a;
    for(i=0;i<n;i++) {
        int temp;
        cin>>temp;
        a.push_back(temp);
    }
    sort(a.begin(),a.end(),compare);
        int m=matrix(n);
    int **helix=(int**)calloc(m+5,sizeof(int*));;
    for(i=0;i<m+5;i++)
        helix[i]=(int*)calloc(n+5,sizeof(int));
    i=j=k=0;
    int up=0,down=0,left=0,right=1;//掌握螺旋方向
    int up_level=m-1,down_level=m,right_level=n,left_level=n;//掌握该方向的长度
    while(k<a.size()){
        if(right){
            helix[i][j]=a[k];
            if(j+1==right_level){
                right=0;
                down=1;
                i++;
                right_level--;
            }
            else j++;
        }
        else if(down){
            helix[i][j]=a[k];
            if(i+1==down_level){
                down=0;
                left=1;
                j--;
                down_level--;
            }
            else i++;
        }
        else if(left){
            helix[i][j]=a[k];
            if(j==n-left_level){
                left=0;
                up=1;
                i--;
                left_level--;
            }
            else j--;
        }
        else if(up){
            helix[i][j]=a[k];
            if(i==m-up_level){
                up=0;
                right=1;
                j++;
                up_level--;
            }
            else i--;
        }
        k++;
    }
    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            cout<<helix[i][j];
            if(j!=n-1) cout<<' ';
        }
        cout<<'\n';
    }
    for(i=0;i<m;i++) free(helix[i]);
    free(helix);
    return 0;
}

测试结果

1051 复数乘法

复数的两种形式,以及乘法的应用。
可以直接用指数形式先计算后,再转化成常规形式,比较简化计算过程。
C++中的三角函数在math.h头文件中

需要注意的是,当A、B在-0.005~0.0之间时,不能输出-0.0
本题A、B有一个为0的情况下,仍要输出该值

#include<iostream>
#include<math.h>
using namespace std;
int main(){
    double r1,p1,r2,p2;
    cin>>r1>>p1>>r2>>p2;
    double r3=r1*r2;
    double p3=p1+p2;
    double a=r3*cos(p3);
    double b=r3*sin(p3);
    if(a>-0.005 && a<0.0) a=0.0;
    if(b>-0.005 && b<0.0) b=0.0;
    if(b<0) printf("%.2f-%.2fi",a,abs(b));
    else printf("%.2f+%.2fi",a,b);
    return 0;
}

测试结果

1052 卖个萌

前三行分别是手、眼、口的符号集合
一行数字是左手、左眼、口、右眼、右手的顺序,对应上面的集合,计数从1开始
符号是一个字符串,包括1-4个字符(使用字符数组更方便判断方括号问题。用string总是错误)

#include<iostream>
using namespace std;
int get(char s[][10]){
    char c;
    int i=0,j=0;
    while((c=getchar())!='\n'){
        if(c=='['){
            j=0;
            while((c=getchar())!=']')
                s[i][j++]=c;
            s[i][j]=0;
            i++;
        }
    }
    return i;
}

int main(){
 char hand[15][10]={0};
 char eye[15][10]={0};
 char mouth[15][10]={0};
 int h=get(hand);
 int e=get(eye);
 int m=get(mouth);
 int n; 
 cin>>n
 while(n--){
        int h1,e1,m1,e2,h2;
        cin>>h1>>e1>>m1>>e2>>h2;
        if((h1<=h && h1>0) && (e1<=e && e1>0) && (m1<=m && m1>0) && (e2<=e && e2>0) && (h2<=h &&h2>0)) cout<<hand[h1-1]<<'('<<eye[e1-1]<<mouth[m1-1]<<eye[e2-1]<<')'<<hand[h2-1]<<'\n';
        else cout<<"Are you kidding me? @\\/@\n";
    }
    return 0;
} 

测试结果

1053 住房空置率

每输入一组数据,判断用电量,计数低于阈值的情况,判断是“可能空置”还是“空置”

#include<iostream>
using namespace std;
int main(){
    int N;
    cin>>N;
    double e;
    cin>>e;
    int D;
    cin>>D;
    double prob_emp=0,emp=0;
    for(int i=0;i<N;i++){
        int n,sig=0,low=0;
        cin>>n;
        if(n>D) sig=1;
        for(int j=0;j<n;j++){
            double E;
            cin>>E;
            if(E<e) low++;
        }
        if(low>n/2 && sig) emp++;
        else if(low>n/2 && !sig) prob_emp++;
    }
    double prob=prob_emp/(double)N;
    double empty=emp/(double)N;
    printf("%.1f%% %.1f%%",prob*100.0,empty*100.0);
    return 0;
}

在这里插入图片描述

1054 求平均值

可用函数:c_str()将string化为char*型,用atof函数直接化为float型

#include<iostream>
#include<string>
#include<iomanip>
#include<math.h>
using namespace std;
bool if_valid(string s){
    int i=0;           //1.整数:超出范围 2.小数:超出范围或精度不对 3.其他非法表达
    int point=0,sig=0;//小数点,负数
    while(i<(int)s.size()){
        if(s[i]=='.'){
            if(s.size()-i>3 || point || !i) return 0; //超精度或已经有小数点或格式不正确
            else point=i;
        }
        else if(!i && s[i]=='-') sig=1;
        else if(s[i]<'0'||s[i]>'9') return 0;
        i++;
    }
 double res=atof(s.c_str());
    if(fabs(res)>1000.00) return 0;
    else return 1;
}

int main(){
    int n;
    cin>>n;
    int i=0,count=n,sig=0;
    float sum=0.0;
    for(;i<n;i++){
        string temp;
        cin>>temp;
        if(if_valid(temp)) {
            sig=1;
            sum+=atof(temp.c_str());
        }
        else {
            cout<<"ERROR: "<<temp<<" is not a legal number"<<endl;
            count--;
        }
    }
    if(!sig) cout<<"The average of 0 numbers is Undefined"<<endl;
    else {
        cout<<"The average of "<<count;
        if(count==1) cout<<" number is ";
        else cout<<" numbers is ";
        cout <<setiosflags(ios::fixed) <<setprecision(2) <<fixed<<sum/count<<endl;
    }
    return 0;
}

测试结果

需要注意的是,当n=1时,输出的英文语法……(虽然输出0的时候并没有这个考虑……)

1055 集体照

读题

一共有K排,每排N/K=m个人,最后一排N-(K-1)*m个人

排序:身高升序,但是如果身高相同,先考虑名字靠前的人!——当排列时我们从身高高的往身高低的逐个考虑,这时要注意把名字靠前的排在后面(身高高的方向)

中间的人站在第m/2+1个,序号从1开始

代码

#include<iostream>
#include<string>
#include<algorithm>
#include<stdlib.h>
#include<vector>
using namespace std;
int m=0;
struct high{
    string name;
    int height;
    high(){
        name="";
        height=0;
    }
};

bool compare(const high& a,const high& b){
    if(a.height==b.height){
        int i=0;
        while(a.name[i]==b.name[i]) i++;
        return a.name[i]>b.name[i];//如果身高相同,应当先考虑名字靠前的那个
    }
    else return a.height<b.height;
}

int list(int l,int n,vector<high>& a){//l:第几排 n:这排几个数
    int begin=l*m;
    int end=begin+n;
    int *res;
    res=new int[n];
    res[n/2]=end-1;//中间的位置是最后那个最高的
    int sig=0,j=1;//左还是右
    for(int i=end-2;i>=begin;i--){
        if(!sig){
            sig=1;
            res[n/2-j]=i;
        }
        else{
            sig=0;
            res[n/2+j]=i;
            j++;
        }
    }
    for(int i=0;i<n;i++) 
       cout<<a[res[i]].name<<(i==n-1?'\n':' ');
    delete(res);
    return 0;
}

int main(){
    int N,K;
    cin>>N>>K;
    m=N/K;
    vector<high> a;
    for(int i=0;i<N;i++){
        high temp;
        cin>>temp.name>>temp.height;
        a.push_back(temp);
    }
    sort(a.begin(),a.end(),compare);
    for(int i=K-1;i>=0;i--){
        if(i==K-1) list(i,N-(K-1)*m,a);
        else list(i,m,a);
    }
    return 0;
}

测试结果

1056 组合数的和

和之前数列的片段和很像,更简单。
可以每个数出现时,只有两种情况:1. 做十位,一共出现N-1次;2.做个位,一共出现N-1次

#include<iostream>
using namespace std;
int main(){
    int n,sum=0;
    cin>>n;
    for(int i=0;i<n;i++){
        int temp;
        cin>>temp;
        sum+=(temp*10+temp)*(n-1);
    }
    cout<<sum;
    return 0;
}

测试结果

1057 数零壹

边输入边转化累加,然后计算二进制数即可

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
    char c;
    int sum=0;
    while((c=getchar())!='\n'){
        if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){
            c=tolower(c);
            sum+=c-'a'+1;
        }
    }
    int count0=0,count1=0;
    while(sum){
        if(sum%2) count1++;
        else count0++;
        sum/=2;
    }
    cout<<count0<<' '<<count1;
    return 0;
}

tolower(char)、toupper(char)函数在< algorithm >中

测试结果

1058 选择题

我用了两个结构,一个是题目,一个是答案,可能有点繁琐了。
之后一边输入学生的答案一边对照之前的题目答案,只要有不统一的就可以判断下一题

#include<iostream>
#include<string>
#include<memory.h>
using namespace std;
struct problem{
    int score,total,right;
    char choose[5];
    problem(){
        score=total=right=0;
        memset(choose,0,sizeof(char));
    }
};

struct answer{
    int num;
    char ans[5];
    answer(){
        num=0;
        memset(ans,0,sizeof(char));
    }
};

int main(){
    int N,M,i,j;
    cin>>N>>M;
    problem a[100];
    for(i=0;i<M;i++){
        cin>>a[i].score>>a[i].total>>a[i].right;
        for(j=0;j<a[i].right;j++) cin>>a[i].choose[j];
    }
    getchar();
    char c;
    int wrong[105]={0};
    for(i=0;i<N;i++){
        answer temp;
        j=0;
        int sco=0;
        while((c=getchar())!='\n'){
            if(c=='('){//进入答案判断
                cin>>temp.num;
                if(temp.num!=a[j].right) wrong[j]++;//选项个数不对
                else{
                    int k=0;
                    for(;k<temp.num;k++) {
                        cin>>temp.ans[k];
                        if(temp.ans[k]!=a[j].choose[k]) break;//选项不对
                    }
                    if(k!=temp.num)  wrong[j]++;
                    else sco+=a[j].score;//数量和选项正确,加分
                }
                j++;//下一题
            }
        }
        cout<<sco<<endl;
    }
    int max=0;
    for(i=0;i<M;i++)
        if(wrong[i]>wrong[max]) max=i;
    if(!wrong[max]){
        cout<<"Too simple"<<endl;
        return 0;
    }else {
        cout<<wrong[max];
        for(i=max;i<M;i++)
            if(wrong[i]==wrong[max]) cout<<' '<<i+1;
        return 0;
    }
}

没什么特别的,细心一点就可以
测试结果

1059 C语言竞赛

也没什么特别的,直接判断

#include<math.h>
using namespace std;
int ranki[10000]={0};
int sig[10000]={0};

bool is_prime(int n){
    int i;
    for(i=2;i<=sqrt(n);i++)
        if(n%i==0) return 0;
    if(i>sqrt(n)) return 1;
}

int main(){
    int N,temp;
    cin>>N;
    for(int i=0;i<N;i++){
        cin>>temp;
        ranki[temp]=i+1;
    }
    int K;
    cin>>K;
    while(K--){
        cin>>temp;
        if(!sig[temp] && ranki[temp]){
            if(ranki[temp]==1)  printf("%04d: Mystery Award\n",temp);
            else if(is_prime(ranki[temp]))  printf("%04d: Minion\n",temp);
            else  printf("%04d: Chocolate\n",temp);
            sig[temp]=1;
        }
        else if(sig[temp])  printf("%04d: Checked\n",temp);
        else if(!ranki[temp])  printf("%04d: Are you kidding?\n",temp);
    }
    return 0;
}

测试结果

1060 爱丁顿数

稍微有点复杂。因为爱丁顿数可能不在所给的数字中。

  1. 所有数都不满足:考虑比第一个数更小的数
  2. 两个数之间的其他数满足
  3. 爱丁顿数就在所给数中

要求的是满足有多少天大于该英里,不是一定要等于

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
    int N;
    cin>>N;
    vector<int> sport;
    for(int i=0;i<N;i++){
        int temp;
        cin>>temp;
        sport.push_back(temp);
    }
    sort(sport.begin(),sport.end());
    int max=sport[0]>N?N:sport[0]-1;//预判:如果后面都不符合,应该是这个结果
    for(int i=0;i<N;i++){
        while(i!=N-1 && sport[i+1]==sport[i]) i++;//相同的数的最后一个位置
        if(i==N-1){
          if(sport[i]==0) max=0;//所有数都是0
          break;
        }
        int j=sport[i];
        while(j<sport[i+1]){
            if(N-i-1>=j && j>max) max=j;//两个数之间的每个数都要考虑一下
            j++;
        }
    }
    cout<<max;
    return 0;
}

测试结果

1061 判断题

非常简单,存储信息后比对即可
这里对于加分,利用了答案只可能是0或1,对所给答案计算然后相加的方式,而不是使用if判断

#include<iostream>
using namespace std;
int main(){
    int M,N,i,sum=0;
    cin>>N>>M;
    int pro[105][2]={0};
    for(i=0;i<M;i++) cin>>pro[i][0];
    for(i=0;i<M;i++) cin>>pro[i][1];
    for(i=0;i<N;i++){
        sum=0;
        for(int j=0;j<M;j++){
            int temp;
            cin>>temp;
            if(pro[j][1]) sum+=temp*pro[j][0];
            else sum+=((temp+1)%2)*pro[j][0];
        }
        cout<<sum<<endl;
    }
    return 0;
}

测试结果

1062 最简分数

先找到以k为分母的分子的范围,然后依次寻找最简分数
注意这里是“之间”,不包括两个给出的数

#include<iostream>
#include<string>
#include<math.h>
using namespace std;
int gcd(int a,int b){
    if(a%b==0) return b;
    else return gcd(b,a%b);
}

bool if_prime(int a,int b){
    if(a<b) {
        int temp=a;
        a=b;
        b=temp;
    }
    if(gcd(a,b)==1) return 1;
    else return 0;
}

int main(){
    int n1,n2,m1,m2,k;
    scanf("%d/%d %d/%d %d",&n1,&m1,&n2,&m2,&k);
    if(n1*m2>n2*m1) {
        int temp=n1;
        n1=n2;
        n2=temp;
        temp=m1;
        m1=m2;
        m2=temp;//n1/m1是较小的分数
    }
    double x=(double)(n1*k)/(double)(m1);//相等时的分子
    int least=floor(x);//求整数
    x=(double)(n2*k)/(double)(m2);
    int max=ceil(x);
    int sig=0;
    for(int i=least+1;i<max;i++){
        if(!if_prime(i,k)) continue;
        else {
            if(sig) cout<<" ";
            cout<<i<<"/"<<k;
            sig=1;
        }
    }
    cout<<endl;
    return 0;
}

测试结果

1063 计算谱半径

#include<iostream>
#include<math.h>
#include<iomanip>
using namespace std;
int main(){
    int n;
    cin>>n;
    double max=0;
    for(int i=0;i<n;i++){
        int a,b;
        cin>>a>>b;
        double s=sqrt(double(a*a+b*b));
        if(s>max) max=s;
    }
    cout<<setiosflags(ios::fixed)<<setprecision(2)<<fixed<<max<<endl;
    return 0;
}

测试结果

1064 朋友数

个人认为这题有歧义。所给的答案是所有不同的各位数和,但我觉得题目的意思应该是得有两个相同的才能算朋友数,都没有相同的怎么能算朋友数,又哪来朋友证号嘞?不知道这样想问题在哪。

#include<iostream>
using namespace std;
int sum[50]={0}; //最大也就是9+9+9+9=36
int main(){
    int n;
    cin>>n;
    int count=0;
    while(n--){
        int temp;
        cin>>temp;
        int s=0;
        while(temp){
            s+=temp%10;
            temp/=10;
        }
        sum[s]++;
        if(sum[s]==1) count++;//可能以后会超过1,但是必须经过1,这样计算避免重复累加
    }
    cout<<count<<endl;
    int sig=0;
    for(int i=0;i<40;i++){
        if(sum[i]>=1){
            if(sig) cout<<' ';
            cout<<i;
            sig=1;
        } 
    }
    return 0;
}

测试结果

1065 单身狗

注意落单的不仅有单身的,还有有对象但是没来的。
我这里设定对应ID的数组数为:

  1. 有对象并且来了:-1
  2. 没有对象:-2
  3. 有对象但没来:-3
  4. 还未判断来没来:
    有对象:对方ID
    没对象:-4
#include<iostream>
using namespace std;
int party[100000];
int main(){
    int m,n,i;
    cin>>n;
    for(i=0;i<100000;i++) party[i]=-4;
    for(i=0;i<n;i++){
        int a,b;
        cin>>a>>b;
        party[a]=b;
        party[b]=a;
    }
    cin>>m;
    int count=0;
    for(i=0;i<m;i++){
        int a;
        cin>>a;
        if(party[a]==-4) {//没对象
            party[a]=-2;
            count++;
        }
        else if(party[a]>=0){//有对象的
            if(party[party[a]]>=0) {
                party[a]=-3;//对象不在
                count++;
            }
            else if(party[party[a]]==-3) {
                party[a]=party[party[a]]=-1; //之前以为不在,现在输入后发现在
                count--;
            }
        }
    }
    cout<<count<<endl;
    int sig=0;
    for(i=0;i<100000;i++){
        if(party[i]==-3 || party[i]==-2) {
            if(sig) cout<<' ';
            printf("%05d",i);
            sig=1;
        }
    }
    return 0;
}

测试结果

1066 图像过滤

注意使用cin和cout时,最后一个测试点会超时,所以我使用了C语言。
除了输入输出头文件声明以外,其他地方不需要修改。使用C++和并用scanf、printf输入输出也可以通过

C代码

//C
#include<stdio.h>
int main(){
    int m,n,min,max,replace;
    scanf("%d %d %d %d %d",&m,&n,&min,&max,&replace);
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            int a;
            scanf("%d",&a);
            if(a>=min && a<=max) printf("%03d",replace);
            else printf("%03d",a);
            if(j!=n-1) printf(" ");
            else printf("\n");
        }
    }
    return 0;
}

C测试结果

C++ 代码

//C++
#include<iostream>
using namespace std;
int main(){
    int m,n,min,max,replace;
    scanf("%d %d %d %d %d",&m,&n,&min,&max,&replace);
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            int a;
            scanf("%d",&a);
            if(a>=min && a<=max) printf("%03d",replace);
            else printf("%03d",a);
            if(j!=n-1) printf(" ");
            else printf("\n");
        }
    }
    return 0;
}

C++测试结果

1067 试密码

逻辑不难,但是小的点特别碎。
用户输入的密码可能有空格。
注意循环时的条件。

#include <iostream>
#include <string>
using namespace std;
int main() {
 string s,temp;
 int n;
 cin>>s>>n;
 getchar();
 while(n) {
        getline(cin, temp);
        if(temp=="#") break;
        if(temp==s) {
            cout<<"Welcome in";
            break;
        }
        else cout << "Wrong password: " << temp<< endl;
        n--;
    }
    if(!n) cout<<"Account locked"<<endl;
    return 0;
}

测试结果

1068 万绿丛中一点红

注意要求是:与周围颜色色差超过tol,且这个颜色色号独一无二

#include<iostream>
#include<memory.h>
#include<cmath>
using namespace std;
int main(){
    int m,n,tol,i,j;
    cin>>m>>n>>tol;
    int **p=new int*[n];
    for(i=0;i<n;i++) p[i]=new int[m];
    for(i=0;i<n;i++)
        for(j=0;j<m;j++) cin>>p[i][j];
    int x=-1,y=-1,color=-1;
    for(i=0;i<n;i++){
        for(j=0;j<m;j++){
            int nor,sou,wes,eas,nw,en,ws,es;
            nor=sou=wes=eas=nw=en=ws=es=tol+1;//没有的话就默认超过200了
            if(i>0) {
                nor=abs(p[i][j]-p[i-1][j]);
                if(nor<=tol) continue;
            }
            if(i<n-1) {
                sou=abs(p[i][j]-p[i+1][j]);
                if(sou<=tol) continue;
                }
            if(j>0) {
                wes=abs(p[i][j-1]-p[i][j]);
                if(wes<=tol) continue;
            }
            if(j<m-1) {
                eas=abs(p[i][j+1]-p[i][j]);
                if(eas<=tol) continue;
            }
            if(i>0 && j>0) {
                nw=abs(p[i][j]-p[i-1][j-1]);
                if(nw<=tol) continue;
            }
            if(i>0 && j<n-1) {
                en=abs(p[i][j]-p[i-1][j+1]);
                if(en<=tol) continue;
            }
            if(i<n-1 && j>0) {
                ws=abs(p[i][j]-p[i+1][j-1]);
                if(ws<=tol) continue;
                }
            if(i<n-1 && j<n-1) {
                es=abs(p[i][j]-p[i+1][j+1]);
                if(es<=tol) continue;
            }
            int sig=0;
            for(int k=0;k<n;k++){
                for(int l=0;l<m;l++){
                    if(k==i && l==j) continue;
                    if(p[k][l]==p[i][j]){
                        sig=1;
                        break;
                    }
                }
            }
            if(sig) continue;
            else{
                if(x!=-1){
                    cout<<"Not Unique";//颜色差够大,颜色又是唯一的,但是之前已经有了符合条件的颜色
                    return 0;
                    }
                else{
                    x=i+1;
                    y=j+1;
                    color=p[i][j];
                }
            }
        }
    }
    if(x==-1) cout<<"Not Exist";
    else cout<<'('<<y<<", "<<x<<"): "<<color;
    for(i=0;i<n;i++) delete p[i];
    delete p;
    return 0;
}

测试结果

1069 微博转发抽奖

依次查找即可。注意对比之前中奖的名单,如果有重复的,向后顺延

#include<iostream>
#include<string>
using namespace std;
string sft[1005];
int gift[1005]={0};
int main(){
    int m,n,s,g=0;
    cin>>m>>n>>s;
    sft[0]="";
    for(int i=1;i<=m;i++)//从1开始编号
        cin>>sft[i];
    while(s<=m){
        int unique=1;
        for(int i=0;i<g;i++)
            if(sft[gift[i]]==sft[s]) unique=0;
        if(unique) {
            cout<<sft[s]<<endl;
            gift[g]=s;
            g++;
            s+=n;
        }
        else s++;
    }
    if(!g) cout<<"Keep going...";
    return 0;
}

测试结果

1070 结绳

编的顺序中,越靠前的,折半的次数越多。为了使绳子尽可能长,应该按从短到长的顺序编

#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
using namespace std;
int main(){
    int n;
    cin>>n;
    vector<double> len;
    for(int i=0;i<n;i++) {
        double temp;
        cin>>temp;
        len.push_back(temp);
    }
    sort(len.begin(),len.end());
    double a=len[0];
    for(int i=1;i<n;i++)
        a=(a+len[i])/2.0;
    cout<<floor(a)<<endl;
    return 0;
}

测试结果

1071 小赌怡情

按顺序判断即可。
注意输出格式

#include<iostream>
using namespace std;
int main(){
    int t,k;
    cin>>t>>k;
    int x=t;
    while(k--){
        int n1,b,t,n2;
        cin>>n1>>b>>t>>n2;
        if(!x){
            cout<<"Game Over."<<endl;
            break;
        }
        if(t>x) {
            cout<<"Not enough tokens.  Total = "<<x<<"."<<endl;
            continue;
        }
        if((n2<n1 && !b)||(n2>n1 && b)) {
            x+=t;
            cout<<"Win "<<t<<"!  Total = "<<x<<"."<<endl;
        }
        else{
            x-=t;
            cout<<"Lose "<<t<<".  Total = "<<x<<"."<<endl;
        }
    }
    return 0;
}

测试结果

1072 开学寄语

可以存储违禁品编号,用循环对照。
也可以用容量10000的数组,对应编号存储1,避免循环。
一个是时间长,一个是空间大,看情况。

#include<iostream>
#include<string>
using namespace std;
int check[10000]={0};
int main(){
    int n,m,temp;
    cin>>n>>m;
    for(int i=0;i<m;i++) {
        cin>>temp;
        check[temp]=1;
    }
    int prob_stu=0,prob_mat=0;
    while(n--){
        string name;
        int k,sig=0;
        cin>>name>>k;
        for(int j=0;j<k;j++){
            cin>>temp;
            if(check[temp]){//违禁物品
                if(!sig) {
                    cout<<name<<":";
                    sig=1;
                }
                cout<<" ";
                printf("%04d",temp);
                prob_mat++;
            }
        }
        if(sig){
            prob_stu++;
            cout<<endl;
        } 
    }
    cout<<prob_stu<<" "<<prob_mat<<endl;
    return 0;
}

注意输出格式

测试结果

1074 宇宙无敌加法器

即每位按照特殊进制计算即可。
计算的顺序和输入的顺序相反,需要先倒序。
注意结果为0的情况以及最高位为0的情况的兼容。

#include<iostream>
#include<string>
using namespace std;
int main(){
    int t[20]={0};
    int pat1[20]={0};
    int pat2[20]={0};
    int res[21]={0};
    string a,b,c;
    int i;
    cin>>a>>b>>c;
    for(i=a.size()-1;i>=0;i--) t[a.size()-1-i]=a[i]-'0';
    for(i=b.size()-1;i>=0;i--) pat1[b.size()-1-i]=b[i]-'0';
    for(i=c.size()-1;i>=0;i--) pat2[c.size()-1-i]=c[i]-'0';
    int c0=0;
    int s=b.size()>c.size()?b.size():c.size();
    for(i=0;i<s;i++){
        int temp=pat1[i]+pat2[i]+c0;
        if(!t[i]) t[i]=10;
        res[i]=temp%t[i];
        c0=temp/t[i];
    }
    res[i]=c0;
    int sig=0;
    for(i=s+1;i>=0;i--){
        if(!res[i] && !sig) continue;
        else{
            sig=1;
            cout<<res[i];
        }
    }
    if(!sig) cout<<"0";
    return 0;
}

测试结果

1075 链表元素分类

将元素分为三种并按原顺序重新连接。
这里如果使用数组存储新的三块数据,因为不知道每个区域数据的多少,容易使用过多的内存。因此最好还是用链表的形式,记录三个链表的头节点和尾节点,再按情况将其连接。

#include<iostream>
using namespace std;
int chain[100000][2];
int main(){
    int first,n,k;
    cin>>first>>n>>k;
    int i;
    for(i=0;i<n;i++){
        int addr;
        cin>>addr;
        cin>>chain[addr][0]>>chain[addr][1];
    }
    i=first;
    int ff,fl,sf,sl,tf,tl;
    ff=fl=sf=sl=tf=tl=-1;
    while(i!=-1){
        if(chain[i][0]<0){
            if(fl==-1) ff=i;
            else chain[fl][1]=i;
            fl=i;
        }
        else if(chain[i][0]>=0&&chain[i][0]<=k){
            if(sl==-1) sf=i;
            else chain[sl][1]=i;
            sl=i;
        }
        else if(chain[i][0]>k){
            if(tl==-1) tf=i;
            else chain[tl][1]=i;
            tl=i;
        }
        i=chain[i][1];
    }
    if(sf!=-1) chain[fl][1]=sf;
    else if(tf!=-1) chain[fl][1]=tf;
    else chain[fl][1]=-1;
    
    if(tf!=-1) chain[sl][1]=tf;
    else chain[sl][1]=-1;

    chain[tl][1]=-1;//将分割的链条连接起来:每个区都存在没有的情况

    if(ff!=-1) first=ff;
    else if(sf!=-1) first=sf;
    else if(tf!=-1) first=tf;//确定首项

    i=first;
    while(i!=-1){
        printf("%05d %d ",i,chain[i][0]);
        if(chain[i][1]==-1) cout<<"-1";
        else printf("%05d\n",chain[i][1]);
        i=chain[i][1];
    }
    return 0;
}

测试结果

1076 wifi密码

只要注意不是按顺序给出ABCD的判断即可。

#include<iostream>
#include<string>
using namespace std;
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        string a,b,c,d;
        cin>>a>>b>>c>>d;
        if(a[2]=='T') cout<<a[0]-'A'+1;
        if(b[2]=='T') cout<<b[0]-'A'+1;
        if(c[2]=='T') cout<<c[0]-'A'+1;
        if(d[2]=='T') cout<<d[0]-'A'+1;
    }
    return 0;
}

测试结果

1077 互评成绩计算

注意去掉不合法情况对计算平均分的影响。并且要记录最高分和最低分。

#include<iostream>
#include<math.h>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        float g2;
        cin>>g2;
        float g1=0;
        int max=-1,min=-1;
        int num=n-1;
        int sig=0;
        for(int j=0;j<n-1;j++){
            int temp;
            cin>>temp;
            if(temp>=0&&temp<=m){
                g1+=temp;
                if(temp>max) max=temp;
                if(temp<min || !sig) {
                    min=temp;
                    sig=1;
                }
            } 
            else num--;
        }
        g1-=(max+min);
        g1=g1/(num-2);
        float res=(g1+g2)/2.0;
        if(res-floor(res)>=0.5) res=ceil(res);
        else res=floor(res);
        cout<<res<<endl;
    }
    return 0;
}

测试结果

1078 字符串压缩与解压

注意空格也算在字符里。
有可能有超过个位数的数字,要进行转为字符串或由字符串转为整数处理。

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
string turn(int a){
    string b;
    while(a) {
        b.push_back(a%10+'0');
        a/=10;
    }
    reverse(b.begin(),b.end());
    return b;
}

int press(string a){
    int i=0;
    int sum=1;
    string b;
    for(;i<a.size()-1;i++){
        if(a[i]==a[i+1]) sum++;
        if(a[i]!=a[i+1] && sum>1) {
            b.append(turn(sum));
            b.push_back(a[i]);
            sum=1;
        }
        else if(a[i]!=a[i+1] && sum==1) b.push_back(a[i]);
    }
    if(sum>1) {
  b.append(turn(sum));
  b.push_back(a[i]);//注意最后一个字符的情况
 }
 else b.push_back(a[i]);
    cout<<b;
    return 0;
}

int release(string a){
    int i=0;
    int sum=0;
    string b;
    for(;i<a.size();i++){
        if(a[i]>='0'&&a[i]<='9') sum=sum*10+a[i]-'0';
        else if((a[i]<'0'||a[i]>'9')&& sum){
            while(sum) {
                b.push_back(a[i]);
                sum--;
            }
        }
        else if((a[i]<'0' || a[i]>'9') && !sum) b.push_back(a[i]);
    }
    cout<<b;
    return 0;
}

int main(){
    char check=getchar();
    getchar();
    string s;
    getline(cin,s);
    if(check=='C') press(s);
    else if(check=='D') release(s);
    return 0;
}

测试结果

1079 延迟的回文数

大整数计算。见前文。

#include<iostream>
#include<memory.h>
#include<string>
using namespace std;
struct bign{
    int d[1010];
    int len;
    bign(){
        memset(d,0,sizeof(d));
        len=0;
    }
};

bign change(string str){
    bign a;
    a.len=str.size();
    for(int i=0;i<a.len;i++){
        a.d[i]=str[a.len-i-1]-'0';
    }
    return a;
};

bign add(bign a,bign b){
   bign c;
   int carry=0;//进位
   for(int i=0;i<a.len || i<b.len;i++){
      int temp=a.d[i]+b.d[i]+carry;
      c.d[c.len++]=temp%10;
      carry=temp/10;
   }
   if(carry !=0){
      c.d[c.len++] =carry;//多的进位
   }
   return c;
};

bign reverse(bign a){
    bign b;
    for(int i=a.len-1;i>=0;i--) b.d[b.len++]=a.d[i];
    return b;
};

bool if_hui(bign a){
    int k=a.len-1;
    for(int i=0;i<k/2+1;i++){
        if(a.d[i]!=a.d[k-i]) return false;
        else continue;
    }
    return true;
};

int main(){
    bign n;
    string s;
    int i=0;
    cin>>s;
    n=change(s);
    if(if_hui(n)){
        for(i=n.len-1;i>=0;i--) cout<<n.d[i];
        cout<<" is a palindromic number.";
        return 0;
    }
    else{
        int j;
        for(j=9;j>=0;j--){
            for(i=n.len-1;i>=0;i--) cout<<n.d[i];
            cout<<" + ";
            bign n_re=reverse(n);
            for(i=n.len-1;i>=0;i--) cout<<n_re.d[i];
            cout<<" = ";
            int c0=0;
            n=add(n,n_re);
            for(i=n.len-1;i>=0;i--) cout<<n.d[i];
            cout<<endl;
            if(if_hui(n)){
                for(i=n.len-1;i>=0;i--) cout<<n.d[i];
                cout<<" is a palindromic number.";
                break;
            }
        }
        if(j<0) cout<<"Not found in 10 iterations.";
    }
    return 0;
}

测试结果

1080 MOOC期终成绩

线性搜索名字将后两张成绩单填入的方式不可取,最后一个测试点会超时。
可以将三张成绩单都用名字排序,然后并行检测,并将结果填入。这样就需要两个结构,可以直接定义两个。
注意,可能有期中、期末参与人数为0的情况,分数有为0的情况。

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<math.h>
using namespace std;
struct sco_list_final{
    string name;
    int score1,score2,score3;
    int sum;
    sco_list_final(){
        name="";
        score1=score2=score3=-1;
        sum=0;
    }
};

struct sco_list{
    string name;
    int g;
    sco_list(){
        name="";
        g=-1;
    }
};

bool compare(const sco_list_final& a,const sco_list_final& b){
    if(a.sum>b.sum) return true;
    else if(a.sum==b.sum){
        if(a.name<b.name) return true;
        else return false;
    }
    else return false;
}

bool compare2(const sco_list& a,const sco_list& b){
    return a.name<b.name;
}

bool compare3(const sco_list_final& a,const sco_list_final& b){
    return a.name<b.name;
}

int main(){
    int p,m,n,i=0;
    cin>>p>>m>>n;
    vector<sco_list_final> score;
    vector<sco_list> gm,gf;
    for(;i<p;i++){
        sco_list_final a;
        cin>>a.name>>a.score1;
        if(a.score1>=200) score.push_back(a);
    }
    for(i=0;i<m;i++){
        sco_list b;
        cin>>b.name>>b.g;
        gm.push_back(b);
    }
    for(i=0;i<n;i++){
        sco_list c;
        cin>>c.name>>c.g;
        gf.push_back(c);
    }
    sort(gm.begin(),gm.end(),compare2);
    sort(gf.begin(),gf.end(),compare2);
    sort(score.begin(),score.end(),compare3);
    int j=0,k=0;
    i=0;
    while(i<p){
        while(j<m && score[i].name>gm[j].name) j++;
        if(j<m && score[i].name==gm[j].name) score[i].score2=gm[j].g;
        while(k<n && score[i].name>gf[k].name) k++;
        if(k<n && score[i].name==gf[k].name) score[i].score3=gf[k].g;
        if(score[i].score2>score[i].score3) score[i].sum=(int)round(0.4*score[i].score2+0.6*score[i].score3);
        else score[i].sum=score[i].score3;
        i++;
    }
    sort(score.begin(),score.end(),compare);
    for(i=0;i<p;i++){
        if(score[i].sum>=60) 
            cout<<score[i].name<<' '<<score[i].score1<<' '<<score[i].score2<<' '<<score[i].score3<<' '<<score[i].sum<<endl;
    }
    return 0;
}

测试结果

round函数:头文件<math.h>,四舍五入(需要编译器支持C99标准,如VS2012就不支持使用)

1081 检查密码

非常简单,直接按照题目所给顺序检查即可。注意按照题目要求,优先考虑数字缺失。

#include<iostream>
#include<string>
using namespace std;
int main(){
    int n;
    cin>>n;
    getchar();
    while(n--){
        string a;
        getline(cin,a);
        if(a.size()<6){
            cout<<"Your password is tai duan le."<<endl;
            continue;
        }
        int sig_e=0,sig_d=0,sig_m=0;
        for(int i=0;i<a.size();i++){
            if((a[i]>='a'&&a[i]<='z') || (a[i]>='A'&&a[i]<='Z')) sig_e++;
            else if(a[i]>='0' && a[i]<='9') sig_d++;
            else if(a[i]=='.') continue;
            else{
                cout<<"Your password is tai luan le."<<endl;
                sig_m=1;
                break;
            }
        }
        if(sig_m==1) continue;
        else if(sig_e && sig_d) cout<<"Your password is wan mei."<<endl;
        else if(sig_e && !sig_d) cout<<"Your password needs shu zi."<<endl;
        else if(!sig_e) cout<<"Your password needs zi mu."<<endl;
    }
    return 0;
}

测试结果

1082 射击比赛

话不多说,上代码

#include<iostream>
#include<string>
using namespace std;
int main(){
    int n;
    cin>>n;
    int min=10000,max=0;
    string min_ID,max_ID;
    while(n--){
        string ID;
        int x,y;
        cin>>ID>>x>>y;
        int res=x*x+y*y;
        if(res>max){
            max=res;
            max_ID=ID;
        }
        if(res<min){
            min=res;
            min_ID=ID;
        }
    }
    cout<<min_ID<<' '<<max_ID;
    return 0;
}

测试结果

1083 是否存在相等的差

可以用数组记录每个差的个数,之后按从大到小的顺序输出

#include<iostream>
#include<math.h>
using namespace std;
int pa[10000]={0};
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        int a;
        cin>>a;
        int d=abs(a-i);
        pa[d]++;
    }
    for(int i=9999;i>=0;i--){
        if(pa[i]>1) cout<<i<<' '<<pa[i]<<endl;
    }
    return 0;
}

测试结果

1084 外观数列

题目的意思是按顺序陈述每个数字及其顺序。并不是能直接代入公式的。

#include<iostream>
#include<string>
using namespace std;
int main(){
    int d,n;
    cin>>d>>n;
    string a;
    a.push_back(d+'0');
    for(int i=1;i<n;i++){
        string temp;
        int sum=1,j=0;
        for(;j<(int)a.size()-1;j++){
            if(a[j]==a[j+1]) sum++;
            else if(a[j]!=a[j+1]){
                temp.push_back(a[j]);
                temp.push_back(sum+'0');
                sum=1;
            }
        }
        temp.push_back(a[j]);
        temp.push_back(sum+'0');
        a=temp;
    }
    cout<<a<<endl;
    return 0;
}

测试结果

1085 PAT单位排行

直接在第一次输入时线性搜索学校的方式是会导致最后两个测试点超时的。
我的方法是可以先用一个vector放所有记录,然后根据学校的名称先排顺序,再将同名的结果计算后放入新的vector中(因为vector的删除代价很大,也可以使用list容器)

transform函数

transform函数:将某操作应用于指定范围的每个元素。

  1. transform(first,last,result,op);

first是容器的首迭代器,last为容器的末迭代器,result为存放结果的容器,op为要进行操作的一元函数对象或sturct、class。

  1. transform(first1,last1,first2,result,binary_op);
    first1是第一个容器的首迭代器,last1为第一个容器的末迭代器,first2为第二个容器的首迭代器,result为存放结果的容器,binary_op为要进行操作的二元函数对象或sturct、class。

注意:第二个重载版本必须要保证两个容器的元素个数相等才行,否则会抛出异常。

代码

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
struct school_test{
    string school;
    float score;
    int student;
    int rank;
    school_test(){
        school="";
        score=0.0;
        student=0;
        rank=1;
    }
};

bool compare1(const school_test& a,const school_test& b){
    return a.school<b.school;
};

bool compare2(const school_test& a,const school_test& b){
    if(a.score!=b.score) return a.score>b.score;
    else if(a.student!=b.student) return a.student<b.student;
    else return a.school<b.school;
}

int main(){
    int n;
    cin>>n;
    vector<school_test> PAT,PATest;
    for(int i=0;i<n;i++){
        school_test a;
        string numb,scho;
        cin>>numb>>a.score>>scho;
        if(numb[0]=='B') a.score/=1.5;
        else if(numb[0]=='T') a.score*=1.5;
        transform(scho.begin(),scho.end(),scho.begin(),::tolower);
        a.school=scho;
        a.student++;
        PAT.push_back(a);
    }
    sort(PAT.begin(),PAT.end(),compare1);
    school_test temp;
    temp.student=0;
    for(int i=0;i<n;i++){
        temp.student++;
        temp.score+=PAT[i].score;
        temp.school=PAT[i].school;
        if(i==n-1 || PAT[i].school!=PAT[i+1].school){
            temp.score=floor(temp.score);
            PATest.push_back(temp);
            temp.student=0;
            temp.score=0;
            temp.school="";
        }
    }
    sort(PATest.begin(),PATest.end(),compare2);
    cout<<PATest.size()<<endl;
    for(int i=0;i<(int)PATest.size();i++){
        if(i && PATest[i].score==PATest[i-1].score) PATest[i].rank=PATest[i-1].rank; 
        else if(i && PATest[i].score!=PATest[i-1].score) PATest[i].rank=i+1;
        cout<<PATest[i].rank<<' '<<PATest[i].school<<' '<<PATest[i].score<<' '<<PATest[i].student<<endl;
    }
    return 0;
}

测试结果

1086 就不告诉你

只需要考虑末尾是0后,倒过来不输出的情况

#include<iostream>
using namespace std;
int main(){
    int a,b;
    cin>>a>>b;
    int c=a*b;
    int sig=0;
    while(c%10==0) c/=10;
    while(c){
        int d=c%10;
        cout<<d;
        c/=10;
    }
    cout<<endl;
    return 0;
}

测试结果

1087 有多少不同的值

需要整数,直接用int的除法即可
另外最大10000,得到的结果最大能到10000*31/30,注意所用容器的大小

#include<iostream>
#include<cmath>
using namespace std;
int accu[10400]={0};
int main(){
    int n,res=0;
    cin>>n;
    for(int i=1;i<=n;i++){
        accu[i/2+i/3+i/5]++;
    }
    for(int i=0;i<10400;i++){
        if(accu[i]>0) res++;
    }
    cout<<res<<endl;
    return 0;
}

测试结果

1088 三人行

乙=y
|甲-乙|=x

然后依次寻找成立的两位正整数即可。
注意丙有可能是小数,不能用int型简化,会出现错误答案

#include<iostream>
#include<math.h>
using namespace std;
int main(){
    int m,x,y;
    cin>>m>>x>>y;
    int jia,yi;
    double bing;
    for(int i=99;i>9;i--){
        jia=i;
        yi=jia%10*10+jia/10;
        bing=(double)yi/(double)y;
        if(fabs(bing-(fabs((double)jia-(double)yi))/x)<1e-6){
            cout<<jia<<' ';
            if(jia>m) cout<<"Cong ";
            if(jia==m) cout<<"Ping ";
            if(jia<m) cout<<"Gai ";
            if(yi>m) cout<<"Cong ";
            if(yi==m) cout<<"Ping ";
            if(yi<m) cout<<"Gai ";
            if(bing>m) cout<<"Cong"<<endl;
            if(bing==m) cout<<"Ping"<<endl;
            if(bing<m) cout<<"Gai"<<endl;
            return 0;
        }
    }
    cout<<"No Solution"<<endl;
    return 0;
}

测试结果

1089 狼人杀-简单版

看起来很复杂。只能使用暴力破解。
题目条件:两个人撒谎,一个好人,一个狼人

使用一个数组装所说的话,一个数组装真实情况。以第一个数组的数为第二个数组的索引,对比后能得到每个人说话的真假

#include<iostream>
using namespace std;
int main(){
    int n;
    cin>>n;
    int *p=new int[n+1];
    int *t=new int[n+1];
    for(int i=1;i<=n;i++) 
        cin>>p[i];
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            fill(t+1,t+n+1,1);
            //如果i和j是狼人,先判断是否确实有两个说谎的人,再判断是否是一个好人一个狼人
            t[i]=-t[i];
            t[j]=-t[j];
            int d=0,dl=0,dh=0;
            int dlk=-1,dhk=-1;
            for(int k=1;k<=n;k++){
                if(p[k]*t[abs(p[k])]<0) {
                    d++;
                    if(t[k]<0) dl++;
                    else dh++;
                }
            }
            if(d==2 && dl==1 && dh==1) {
                cout<<i<<' '<<j<<endl;
                return 0;
            }
        }
    }
    cout<<"No Solution"<<endl;
    return 0;
}

测试结果

1090 危险品装箱

注意多对中会出现重复的危险品——考虑使用集合容器

set容器

set是一个集合容器,元素不允许重复,默认升序排列。不支持索引。

begin();            // 返回指向第一个元素的迭代器
end();              // 返回指向最后一个元素的迭代器
insert()//在集合中插入元素 
clear();            // 清除所有元素
count();            // 返回某个值元素的个数 
empty();            // 如果集合为空,返回true 
erase()//删除集合中的元素 
find()//返回一个指向被查找到元素的迭代器 
size()//集合中元素的数目

equal_range();      //返回集合中与给定值相等的上下限的两个迭代器 
get_allocator()//返回集合的分配器 
lower_bound()//返回指向大于(或等于)某值的第一个元素的迭代器 
upper_bound()//返回大于某个值元素的迭代器 
key_comp()//返回一个用于元素间值比较的函数 
max_size()//返回集合能容纳的元素的最大限值 
rbegin()//返回指向集合中最后一个元素的反向迭代器 
rend()//返回指向集合中第一个元素的反向迭代器  
swap()//交换两个集合变量 

fill函数

为了大批量给数组赋值,可以使用fill或fill_n函数

void fill(ForwardIt first, ForwardIt last, const T& value); 

void fill_n(OutputIt first, size n, const T& value); 

代码

#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
set<int> rec[100010];
int sig[100010]={0};
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        int g1,g2;
        cin>>g1>>g2;
        rec[g1].insert(g2);
        rec[g2].insert(g1);
    }
    for(int i=0;i<m;i++){
        fill(sig,sig+100010,0);
        int k,j,s=1;
        cin>>k;
        for(j=0;j<k;j++){
            int id;
            cin>>id;
            if(sig[id]==0){
                sig[id]=1;
                for(set<int>::iterator it=rec[id].begin();it!=rec[id].end();it++)
                    sig[*it]=1;
            }
            else s=0;//这里如果break最后两个测试点就会报错,我不懂为什么,不知道有没有大神肯赐教
        }
        if(s) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

测试结果

1091 N-自守数

很简单,一个个检验即可。
注意保留初始数据用于输出

#include<iostream>
using namespace std;
int main(){
    int m;
    cin>>m;
    for(int i=0;i<m;i++){
        int k,n;
        cin>>k;
        for(n=0;n<10;n++){
            int nk=n*k*k;
            int temp1=k,temp2=nk;
            while(temp1){
                if(temp2%10 == temp1%10){
                    temp2/=10;
                    temp1/=10;
                }
                else break;
            }
            if(temp1==0){
                cout<<n<<' '<<nk<<endl;
                break;
            }
        }
        if(n==10) cout<<"No"<<endl;
    }
    return 0;
}

测试结果

1092 最好吃的月饼

将对应的销量加起来,得到各类月饼的销量。
然后按顺序判断最大值。

#include<iostream>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    int p[1000]={0};
    int max=0;
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            int sco;
            cin>>sco;
            p[j]+=sco;
            if(p[j]>p[max]) max=j;
        }
    }
    int sig=0;
    cout<<p[max]<<endl;
    for(int i=0;i<n;i++){
        if(p[i]==p[max]) {
            if(sig) cout<<' '<<i+1;
            else cout<<i+1;
            sig=1;
        }
    }
    return 0;
}

测结果

1093 字符串A+B

使用数组记录每个字符的使用情况,如果已经使用,则不再输出。

#include<iostream>
#include<string>
using namespace std;
int sig[200]={0};
int main(){
    string a,b;
    getline(cin,a);
    getline(cin,b);
    for(int i=0;i<a.size();i++){
        if(sig[a[i]]==0){
            cout<<a[i];
            sig[a[i]]=1;
        }
        else continue;
    }
    for(int i=0;i<b.size();i++){
        if(sig[b[i]]==0){
            cout<<b[i];
            sig[b[i]]=1;
        }
        else continue;
    }
    return 0;
}

测试结果

1094 谷歌的招聘

给出的数字是大整数,但是计算过程中并不是,所以只要将数字串存入数组,将所需的数字部分取出判断即可。
由于k已知,所以每次右移一位取新的数时,可以直接减去原本最高位乘以10^k

#include<iostream>
#include<string>
#include<memory.h>
#include<math.h>
using namespace std;
bool if_prime(int n){
    for(int i=2;i<sqrt(n);i++){
        if(n%i==0) return false;
    }
    return true;
}

int main(){
    int num[1005]={0};
    int l,k;
    cin>>l>>k;
    int i,f,n=0;
    int high=1;
 getchar();
    for(i=0;i<l;i++) {
  char c;
  cin>>c;
  num[i]=c-'0';
 }
    for(i=0;i<k;i++){
        n=n*10+num[i];           //第一个k位数(10位之内,在int型范围内)
        high*=10;
    }
    f=num[0];
    for(i=k-1;i<l;i++){
        if(i!=k-1){
            n=n*10+num[i]-f*high;
            f=num[i-k+1];
        }
        if(if_prime(n)) break;
        else continue;
    }
    if(i==l) cout<<"404";
    else {
        if(n<high/10){
            for(int j=high/10;j>=10;j/=10){
                if(n<j) cout<<'0';
                else break;
            }
        }
        cout<<n;
    }
    return 0;
}

注意输出时前导零要补齐

测试结果

1095 解码PAT准考证

很麻烦的一道题,而且使用C++常用的cin和cout非常容易超时,最后将大多数都换成了printf和scanf才算通过。
注意输出时的顺序要求。

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
struct PATinfo{
    string sn;
    char level;
    int number;
    string date;
    int iden,score;
};

PATinfo in[10005];

PATinfo change(string s,int sco){
    PATinfo a;
    a.sn=s;
    a.level=s[0];
    a.number=(s[1]-'0')*100+(s[2]-'0')*10+s[3]-'0';
    a.date.assign(s,4,6);
    a.iden=(s[10]-'0')*100+(s[11]-'0')*10+(s[12]-'0');
    a.score=sco;
    return a;
}//拆解信息

bool compare(const PATinfo& a,const PATinfo& b){
    if(a.score==b.score) return a.sn<b.sn;
    else return a.score>b.score;
}

void level_score(char a,int n){
    printf("1 %c\n",a);
    vector<PATinfo> sta;
    for(int i=0;i<n;i++)
        if(in[i].level==a) sta.push_back(in[i]);
    if(sta.size()==0){
        printf("NA\n");
        return;
    }
    sort(sta.begin(),sta.end(),compare);
    for(int i=0;i<sta.size();i++)
  printf("%s %d\n",sta[i].sn.c_str(),sta[i].score);
    return;
}//case1

void exam_sta(int w,int n){
    printf("2 %d\n",w);
    int sum=0;
    int stu=0;
    for(int i=0;i<n;i++){
        if(in[i].number==w){
            sum+=in[i].score;
            stu++;
        }
    }
    if(stu==0){
        cout<<"NA"<<endl;
        return;
    }
    printf("%d %d\n",stu,sum);
    return;
}//case2

void date_sta(string d,int n){
    cout<<"3 "<<d<<endl;
    int record[1000]={0};
    int sig=0,max=0;
    for(int i=0;i<n;i++){
        if(in[i].date==d){
            record[in[i].number]++;
            if(record[in[i].number]>max) max=record[in[i].number];
            sig=1;
        }
    }
    if(!sig){
        printf("NA\n");
        return;
    }
    for(int i=max;i>0;i--){
        for(int j=101;j<=999;j++){
            if(record[j]==i){
                printf("%d %d\n",j,record[j]);
            }
        }
    }
    return;
}//case3

int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++){
        string temp;
        int s;
        cin>>temp;
  scanf("%d",&s);
        in[i]=change(temp,s);
    }
    for(int i=0;i<m;i++){
        int c,temp;
        char l;
        string d;
        scanf("%d ",&c);
        cout<<"Case "<<i+1<<": ";
        switch(c){
            case 1:scanf("%c",&l);
                   level_score(l,n);
                   break;
            case 2:scanf("%d",&temp);
                   exam_sta(temp,n);
                   break;
            case 3:cin>>d;
                   date_sta(d,n);
                   break;
            default:break;
        }
    }
    return 0;
}

在这里插入图片描述

————————————————————————————————————转载请注明出处

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值