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

算法笔记3.1节

万万没想到刚开始就有A级题,英语阅读理解始める!

A1042

(1)自己尝试+参考思路

 1 #include <cstdio>
 2 #include <string>
 3 
 4 char mp[5] = {'S','H','C','D','J'};  //很有趣的操作
 5 
 6 int main(){
 7     int k;
 8     scanf("%d",&k);
 9     int start[55] = {0};
10     int next[55] = {0};
11     for(int j=1;j<=54;j++){
12         int temp;
13         scanf("%d",&temp);
14         start[j] = j;
15         next[j] = temp;
16     }
17     int end[55] = {0};
18     for(int i=0;i<k;i++){
19         for(int j=1;j<=54;j++){
20             end[next[j]] =start[j];
21         }
22         for(int j=1;j<=54;j++){
23             start[j] =end[j];
24         }
25     }
26     for(int i=1;i<=54;i++){
27         printf("%c%d",mp[(start[i]-1)/13],(start[i]-1)%13+1); 
28         if(i!=54) printf(" ");
29     }
30     
31 }

这题需要开三个数组是没想到的,需要有一个next数组是不变的,否则每次循环的时候没法保留原始的交换顺序。

总得来讲a级题的思考能力要求确实提高了很多。

然后就是打印的方式很值得学习 。

尽管需要说的不多,但是这道题需要当作一个重点以后复习。

 

A1046

 

总之二重循环会超时,没啥办法,错的就不贴了。看下答案,

根据答案中要求查询的复杂度为O(1),所以需要预处理。

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int MAXN = 100005;
 6 int dis[MAXN],A[MAXN];  
 7 int main(){
 8     int sum =0,query,n,left,right;
 9     scanf("%d",&n);
10     for(int i=1;i<=n;i++){
11         scanf("%d",&A[i]);
12         sum += A[i]; //累加sum
13         dis[i] = sum; //预处理dis数组,防止超时。
14     }
15     scanf("%d",&query);
16     for(int i=0;i<query;i++){ //query个查询
17         scanf("%d%d",&left,&right); //left->right;
18         if(left>right) swap(left,right); //algorithm中的函数
19         int temp =  dis[right-1]- dis[left-1];
20         printf("%d\n",min(temp,sum-temp));
21     }
22     return 0;
23 }

这题最好能背过,也算是正式开启算法学习的一道题了 。

总得来讲需要注意以下几点:

①给数组开空间的时候不用太在意大小。

②对数组进行预处理,多存几个数组,这样最节约时间。

③记录总距离,然后通过总距离减当前距离获得另一个距离。这个数据结构其简化后只有顺时针和逆时针的一条线,答案已经是抽象的最高层次了。

 

A1065

 

 肯定有坑,不知道在哪,写完部分正确,看答案找坑。

思路:

long long的范围是[-2^63,2^63),两个整数相加可能会溢出。在计算机组成原理中会指出,如果两个正数之和等于负数或是两个负数之和等于正数,那么就是溢出。对于溢出后的具体范围,可以进行如下分析:

① 当A+B>=263时,显然有A+B>C成立,但是A+B会因超过long long的正向最大值而发生正溢出。由于题目给定的A和B的最大均为263-1,故A+B的最大值为264-2,因此使用long long存储正溢出后的值的区间为[-263,-2](由(2^64-2)%(2^64)=-2可得右边界)。所以当A>0,B>0,A+B<0时为正溢出,输出true

②当A+B<-263时,显然有A+B<C成立,但A+B会因超过long long的负向最小值而发生负溢出。由于题目给定的A和B的最小均为-264,故A+B最小为-264。因此使用long long负溢出时后的值的区间为[0,263(由(-264)%264=可得右边界)。

所以当A<0,B<0,A+B>=0时为负溢出,输出false。

③当没有溢出的情况下,正常考虑。

 

注意点:

①经测试,数据中没有A或B取到2^63的情况,因此题目中的数据范围可能是写错了,应该是[-2^63,2^63)才更符合数据,否则就要用带负数的大整数运算了(因为long long存储2^63时会自动变成-2^63,无法区分左右边界)。

②A+B必须存放到long long型变量中才能与C进行比较,而不可以在if条件中直接相加与C比较,否则会造成后两组数据错误(?)

 

然后答案差不多就这样了。

 1 #include <cstdio>
 2 
 3 int main(){
 4     int n;
 5     scanf("%d",&n);
 6     for(int i=1;i<=n;i++){
 7         long long a,b,c;
 8         scanf("%lld%lld%lld",&a,&b,&c);
 9         long long res = a + b;
10         bool flag;
11         if(a>0 && b>0 && res<0) flag = true; //正溢出为true
12         else if(a<0 && b<0 && res>=0) flag = false; //负溢出为false
13         else if(res>c) flag = true;
14         else flag =false;
15         if(flag == true){
16             printf("Case #%d: true\n",i);
17         }
18         else{
19             printf("Case #%d: false\n",i);
20         }
21     }
22 }

 

B1010

 

。。都标红好了

(1)自己尝试

 1 #include <cstdio>
 2 
 3 //需要用while EOF读入数据
 4 
 5 int main(){
 6     int k,e;
 7     while(scanf("%d%d",&k,&e)!=EOF){
 8         if(e!=0) printf("%d %d ",k*e,e-1);
 9     }
10 }

想当然地写了两行,发现跳进了深坑,这个没啥太好办法解决最后的空格问题。

去参考下答案。

(2)参考答案

 1 #include <cstdio>
 2 
 3 //需要用while EOF读入数据
 4 
 5 int main(){
 6     int a[1010] = {0};
 7     int k,e,count=0; //k为系数,e为指数,count计数不为零的导数的个数。
 8     while(scanf("%d%d",&k,&e)!=EOF){
 9         a[e] = k;
10     }
11     a[0] =0; //零次求导之后直接为0。
12     for(int i=1;i<=1000;i++){
13         a[i-1] = a[i]*i; //求导公式
14         a[i] = 0; //此句不可省
15         if(a[i-1]!=0) count++;
16     }
17     if(count==0) printf("0 0"); //特例
18     else{
19         for(int i=1000;i>=0;i--){ //指数从高到低输出
20             if(a[i] != 0){
21                 printf("%d %d",a[i],i);
22                 count--;
23                 if(count != 0) printf(" ");
24             }
25         }
26     }
27     return 0;
28 }

实际上这题可以自己写下试试,不过那个“如果求导之后没有任何非零项,需要输出 0 0,这是本题的一个陷阱应该发现不了。总得来讲学到怎么用while EOF是最主要的。

 

A1002

(1)自己尝试

 1 1002
 2 相加为0的值不出现,注意最前边也需要改
 3 #include<iostream>
 4 #include<set>
 5 using namespace std;
 6 double num[10005];
 7 int main(){
 8     int n;
 9     set<int>s;
10     cin>>n;
11     for(int i=0;i<n;i++){
12         int a ;
13         double b;
14         cin>>a>>b;
15         num[a]+=b;
16     }
17     cin>>n;
18     for(int i=0;i<n;i++){
19         int a ;
20         double b;
21         cin>>a>>b;
22         num[a]+=b;
23     }
24     int count=0;
25     for(int i=0;i<10005;i++){
26         if(num[i]!=0){
27             count++;
28         }
29     }
30     cout<<count;
31     for(int i=10000;i>=0;i--){
32         if(num[i]!=0){
33             printf(" %d %0.1f", i, num[i]);
34             //cout<<" "<<i<<" "<<num[i];
35         } 
36     }
37     return 0;
38 }

这题没太多值得说的。

 

A1009 

 

注意一下参考答案使用结构体的写法。

 1 #include <cstdio>
 2 struct Ploy{
 3     int exp;//指数
 4     double cof; //系数
 5 } ploy[1001]; //第一个多项式
 6 
 7 double ans[2001];//存放结果
 8 int main(){
 9     int n,m,number = 0;
10     scanf("%d",&n); //第一个多项式中非零系数的项数。
11     for(int i=0;i<n;i++){
12         scanf("%d %lf",&ploy[i].exp,&ploy[i].cof);
13     }
14     scanf("%d",&m); //第二个多项式中非零系数的项数。
15     for(int i=0;i<m;i++){
16         int exp;
17         double cof;
18         scanf("%d %lf",&exp,&cof); //第二个多项式的指数和系数
19         for(int j=0;j<n;j++){ //与第一个多项式中的每一项相加
20             ans[exp+ploy[j].exp] += (cof*ploy[j].cof);            
21         }
22     }
23     for(int i=0;i<=2000;i++){
24         if(ans[i]!=0.0) number++; //积累非零系数的项数
25     }
26     printf("%d",number);
27     for(int i=2000;i>=0;i--){
28         if(ans[i]!=0.0){
29             printf(" %d %.1f",i,ans[i]);
30         }
31     }
32     
33 }

 

posted @ 2021-02-02 22:34  魂淡菌  阅读(68)  评论(0)    收藏  举报