【PAT刷题】快速产出垃圾——2020-2-1

前言:

从今天开始写博客了,主要用来督促一下自己。

 

算法笔记3.1节

B1032

 
(1)自己尝试
 1 #include <cstdio>
 2 
 3 // 可以把题设条件写到最上边
 4 const int maxn =100010;
 5 int school[maxn] = {0};
 6 
 7 int main(){
 8     int n;
 9     scanf("%d",&n);
10     for(int i=0;i<n;i++){
11         int schoolID,schoolSc;
12         scanf("%d%d",&schoolID,&schoolSc);
13         school[schoolID] +=schoolSc;
14     }
15     int maxSc=0;
16     int index = 0;
17     for(int i=0;i<maxn;i++){
18         if(school[i]>maxSc){
19             maxSc = school[i];
20             index = i;
21         }
22     }
23     printf("%d %d",index,maxSc);
24 }
申请数组和数组长度的时候看了下答案,C语言不够熟练
个人感觉完全遍历数组效率较低,后根据答案改进。
 
(2)答案
 1 #include <cstdio>
 2 
 3 // 可以把题设条件写到最上边
 4 const int maxn =100010;
 5 int school[maxn] = {0};
 6 
 7 int main(){
 8     int n,schoolID,schoolSc;
 9     scanf("%d",&n);
10     for(int i=0;i<n;i++){
11         scanf("%d%d",&schoolID,&schoolSc);
12         school[schoolID] +=schoolSc;
13     }
14     int maxSc=-1,index=1;
15     for(int i=1;i<=n;i++){
16         if(school[i]>maxSc){
17             maxSc = school[i];
18             index = i;
19         }
20     }
21     printf("%d %d",index,maxSc);
22     return 0;
23 }

 

首先审题可以看到学校的编号从1开始连续编号,说明学校数量是小于n的,这就解决了上边的遍历位数过多的问题。
另外,需要考虑maxSc=-1和index=1这两个数,最大值如果设置为0可能会出现分数都为0的情况,对于这种情况比较难判断,习惯性会选择一个不会出现的分数;index=1是因为学校编号从1开始。
总结来看自己写的时候的问题就是时间和空间两方面都非常浪费。
 

B1011

(1)自己尝试
 1 #include <cstdio>
 2 
 3 int main(){
 4     int n;
 5     scanf("%d",&n);
 6     for(int i=0;i<n;i++){
 7         int a,b,c;
 8         scanf("%d%d%d",&a,&b,&c);
 9         if(a+b>c) printf("Case #%d: true\n",i+1);
10         else printf("Case #%d: false\n",i+1);
11     }
12 }

 

实际上自己也觉得不太对,把该踩的坑都踩了。。
 
看了下后边的注意点
①要实现执行T次循环,可以用While(T--)
②题目给出的范围是[-2^31,2^31],首先需要知道Int型的数据范围是[-2^31,2^31-1],另外两个int变量相加,最后可能超过int型,所以必须使用long。而且输入输出格式必须是%lld,否则会返回代码错误。
 
(2)改进一下
 1 #include <cstdio>
 2 
 3 int main(){
 4     long n;
 5     scanf("%lld",&n);
 6     for(int i=0;i<n;i++){
 7         long a,b,c;
 8         scanf("%lld%lld%lld",&a,&b,&c);
 9         if(a+b>c) printf("Case #%d: true\n",i+1);
10         else printf("Case #%d: false\n",i+1);
11     }
12 }
 
都改成long然后输入格式改了之后基本没啥事了,看下答案继续改进一下。
 
答案不同的地方是因为用while写的循环导致多了个tcase的变量,其他基本没什么区别,还有多了个return 0,还是注意写一下吧。
 
 

B1016

这题看到之后第一个想到的是转成字符串进行操作,这里是弱项,先自己写一下试试,应该很慢就是了。

 

……既然有答案还是学习答案的做法吧,之前的做法实在太蠢了。

 

(1)直接参考答案

思路:

令P_A初值为0,枚举A中的每一位,如果该位恰好等于D_A,则令P_A=P_A*10+D_A。这样当枚举完A中每一位之后,就得到了P_A。

得到P_A的过程解决了字符串转换的问题,但是枚举的过程并没有。继续往后看

注意点:

10^10超过了int范围,所以要用long long来存放A和B。

(补充long和long long的区别定义是long至少不小于int,long long至少不小于long.在32位机器中,一般long和int同,为32,long long为64)

源代码:

枚举的过程直接把a干掉了……所以还是通过取余数和除解决的问题。

先自己写一遍试试。

 1 #include <stdio.h>
 2 #include <string>
 3 using namespace std;
 4 
 5 int main(){
 6     long long a,da,b,db;
 7     scanf("%lld%lld%lld%lld",&a,&da,&b,&db);
 8     long long pa=0,pb=0;
 9     while(a){
10         if(a%10==da) pa= pa*10+da;
11         a /=10;
12     }
13     while(b){
14         if(b%10==db) pb = pb*10+db;
15         b/=10;
16     }
17     printf("%lld",pa+pb);
18 }

基本和答案一样。

 

总结:

①枚举整数的时候可以通过除以10和对10求余进行。

②对于拼合成整数同样可以通过乘以10再补充个位进行。

③综合前两条,相当于个位是栈顶,先进先出

④int的范围是2*10^9正负注意这个坑

 

B1026

这题关键保留几位小数的问题和数字格式转换的问题。

 

感觉数据类型方面非常混乱,自己写的代码也很有问题,所以直接贴参考答案。

 

其中当C2-C1的末两位不小于50时,说明C2-C1除以100之后要四舍五入。

涉及浮点数会变得复杂,所以还是操纵整数比较好。

 1 #include <cmath>
 2 #include <cstdio>
 3 
 4 const int CLK_TCK= 100;
 5 int main(){
 6     int c1,c2;
 7     scanf("%d%d",&c1,&c2);
 8     if((c2-c1)%100>=50) c2+=50;
 9     int time = (c2-c1)/CLK_TCK;
10     int hh = time/3600;
11     int mm = (time%3600)/60;
12     int ss = time%60;
13     printf("%02d:%02d:%02d\n",hh,mm,ss);
14    return 0;
15 }

所以总得来讲其实就是四舍五入时最方便的做法就是操作之前的整数。

这样就和答案差不多了,记得printf后的\n和return 0。


B1046

(1)自己尝试

 1 #include <cstdio>
 2 
 3 int main(){
 4     int n;
 5     scanf("%d",&n);
 6     int a,b;
 7     while(n--){
 8         int a1,a2,b1,b2;
 9         scanf("%d%d%d%d",&a1,&a2,&b1,&b2);
10         if(a1+b1==a2 && a1+b1==b2){
11             
12         }
13         else if(a1+b1==a2) b++;
14         else if(a1+b1==b2) a++;
15     }
16     printf("%d %d",a,b);
17 }

考了个选择逻辑,基本没太多可说的,根据答案改进一下。

 

(2)参考答案

参考答案里用了另一种逻辑,即异或逻辑,一个相等另一个不相等,基本是同样的道理,不再赘述。

 

B1008

 

题目中有一句移动数据次数尽可能少,可能涉及超时问题,不过第一遍写的时候先不管。

既然说数组就用下数组好了。

(1)自己尝试

 1 #include <cstdio>
 2 
 3 int main(){
 4     int n,m;
 5     scanf("%d%d",&n,&m);
 6     int counts[101];
 7     for(int i=0;i<n;i++){
 8         scanf("%d",&counts[(i+m)%n]);
 9     }
10     for(int i=0;i<n;i++){
11         if(i==n-1) printf("%d",counts[i]);
12         else printf("%d ",counts[i]);
13     }
14 }

申请数组取模就好了,没太多好说的

 

(2)参考答案

感觉答案更复杂就不贴了 ,注意5.2节会有移动次数最少的操作数组做法,在之后需要注意一下。

 

 

B1012

(1)自己尝试

#include <cstdio>

int main(){
    int n;
    scanf("%d",&n);
    int sums[5] = {0};
    int flag = 1;
    int count3;
    for(int i=0;i<n;i++){
        int a;
        scanf("%d",&a);
        switch(a%5){
            case 0:
                if(a%2==0) sums[0] += a;
                break;
            case 1:
                sums[1] += a*flag;
                flag = -flag;
                break;
            case 2:
                sums[2]++;
                break;
            case 3:
                sums[3]+= a;
                count3++;
                break;
            case 4:
                if(sums[4]<a) sums[4] =a;
                break;
        }
    }
    double sums3 = (double)sums[3]/(double)count3;
    printf("%d %d %d %.1f %d",sums[0],sums[1],sums[2],sums3,sums[4]);
}

自己的时候没有考虑输出N的问题,考虑之后改起来很麻烦,所以直接看答案了。

 

(2)参考答案

实际上看了答案也很麻烦,把打印写开就好了,尝试一下。

 1 #include <cstdio>
 2 
 3 int main(){
 4     int n;
 5     scanf("%d",&n);
 6     int sums[5] = {0};
 7     int flag = 1;
 8     int count3;
 9     for(int i=0;i<n;i++){
10         int a;
11         scanf("%d",&a);
12         switch(a%5){
13             case 0:
14                 if(a%2==0) sums[0] += a;
15                 break;
16             case 1:
17                 sums[1] += a*flag;
18                 flag = -flag;
19                 break;
20             case 2:
21                 sums[2]++;
22                 break;
23             case 3:
24                 sums[3]+= a;
25                 count3++;
26                 break;
27             case 4:
28                 if(sums[4]<a) sums[4] =a;
29                 break;
30         }
31     }
32     double sums3 = (double)sums[3]/(double)count3;
33     if(sums[0]==0) printf("N ");
34     else printf("%d ",sums[0]);
35     if(sums[1]==0) printf("N ");
36     else printf("%d ",sums[1]);
37     if(sums[2]==0) printf("N "); //实际上是这里的问题。和下边同理
38     else printf("%d ",sums[2]);
39     if(sums[3]==0) printf("N ");
40     else printf("%.1f ",sums3);
41     if(sums[4]==4) printf("N"); //这里4写成0了,改了之后还有一个过不了,应该是余数是4等于0的情况…倒也不是。
42     else printf("%d",sums[4]);
43 }

修改之后还是过不了的,再读题找找坑。

 

总得来讲答案记录数量的做法是正确的,如果不记录的话会混淆结果和判断条件,所以一般还是不要节省空间,空间能费一些是有好处的。

 

 

B1018

这个题可以很好说明什么时候需要写成函数。首先我们可以看到读入的内容为字符,而为了操作方便我们最好需要将输入内容转化为整数。

而这里如果对每种情况进行枚举再去转化可能会很繁琐(共要处理2*3=6种情况),而为了简化情况数量我们可以将某些部分进行抽象,比如变量的持有者甲或者乙,这样我们可以减少一半的代码量,而这个操作可以单独写一个change函数来实现。

而转化规则就通过需要输出的字典序来建立映射即可。

从这个题中可以学习很多经验,应该重点标记,以后多进行复习。

 

(1)自己尝试+思路

 1 #include <cstdio>
 2 
 3 int change(char c){
 4     if(c=='B') return 0;
 5     if(c=='C') return 1;
 6     if(c=='J') return 2;
 7     return -1;
 8 }
 9 int findmax(int sum[]){
10     int index=0;
11     int max=-1;
12     for(int i=0;i<3;i++){
13         if(sum[i]>max)
14         {
15            max= sum[i];
16            index =i;
17         }
18     }
19     return index;
20 }
21 int main(){
22     int n;
23     scanf("%d",&n);
24     char hash[3]={'B','C','J'};
25     int jieguo[3]={0};
26     int sumA[3]={0};
27     int sumB[3]={0};
28     for(int i=0;i<n;i++){
29         char a,b;
30         getchar(); //这里的getchar用来吸收换行符
31         scanf("%c %c",&a,&b);
32         if(a==b) jieguo[1]++;
33         else if(a=='B' && b=='C') {jieguo[0]++; sumA[change(a)]++;}
34         else if(a=='C' && b=='J') {jieguo[0]++; sumA[change(a)]++;}
35         else if(a=='J' && b=='B') {jieguo[0]++; sumA[change(a)]++;}
36         else {jieguo[2]++; sumB[change(b)]++;}
37     }
38     printf("%d %d %d\n",jieguo[0],jieguo[1],jieguo[2]);
39     printf("%d %d %d\n",jieguo[2],jieguo[1],jieguo[0]);
40     printf("%c %c",hash[findmax(sumA)],hash[findmax(sumB)]);
41 }

 

(2)参考答案

思路很有趣,抄一下:

思路

步骤1:考虑到最后需要输出字典序最小的解,不妨将三种手势按字典序排序,即B、C、J。可以发现,这个顺序又恰好是循环相克顺序,即B战胜C、C战胜J、J战胜B,因此不妨将B、C、J对应为0、1、2,作为一维数组mp的三个元素:mp[0]='B',mp[1]=‘C’,mp[2]='J',同时写一个函数change(char c)来将手势对应到数字。

步骤2:对每组读入的甲乙手势c1和c2,先将其通过change函数转换为数字k1和k2,然后判断该局输赢。由于设置的顺序恰好就是循环相克的顺序,因此k1胜k2的条件是(k1+1)%3 = k2,而k1平k2的条件是k1==k2,k1输k2的条件是(k2+1)%3==k1

     在得到该局输赢后,对甲、乙的胜、平、负次数进行操作,并对赢得该局的一方的手势次数加1。

步骤3:比较得到胜利次数最多的手势。

 

注意点

由于scanf使用%c时会将换行符\n读入,因此需要在合适的地方用getchar吸收换行符(成功踩到这个坑了)。程序输入后闪退,基本就是这个问题导致的。

②本体如果使用大量if else语句也可以,但是写法不够简洁,因此要考虑将字母转换为数字的思路,则会简单许多。

 

实际上还是很麻烦,参考答案就不抄了,关键学习判断胜负的条件、转换数字的思路以及字符格式的处理。

 

 

今天就到这里了(实际上标题是1-31……嘛嘛第一天就摸鱼还是不太合适的啊哈哈,啊哈哈哈。)

 

 

posted @ 2021-02-01 23:50  魂淡菌  阅读(73)  评论(0)    收藏  举报