【题解】2021PAT春季甲级


【7-1 Arithmetic Progression of Primes】

筛法预处理区间内的素数

因为已知数列长度,如果知道数列第一、二个数即可求得整个数列
暴力枚举前两个数,看后续是否满足{①在区间内②是素数}两个条件
在所有找出的符合的数列中按题目要求得到最后应该输出的那个数列

特殊情况:
①(n=1 || n==2&&m==2 || n>2&&找不到符合数列)时输出区间内最大的素数
②n==2&&m>2时输出2和区间内最大的素数

 1 #include<cstdio>
 2 using namespace std;
 3 
 4 int n,m,top,pri[100100],anstop,ans[10000][20];
 5 bool f[100100],fail;
 6 
 7 int main()
 8 {
 9     scanf("%d%d",&n,&m);
10     f[1]=1;                    //筛法求素数,f[x]=0表示x是素数 
11     for (int i=2; i<=100000; ++i) if (!f[i])
12     {
13         int j=i+i;
14         while (j<=100000) {f[j]=1; j+=i;}
15     }
16     for (int i=2; i<=100000; ++i) if (!f[i]) pri[++top]=i;    //收集素数以便枚举 
17     while (pri[top]>m) top--;
18     fail=0;        //fail=1表示特殊情况1 
19     if (n>2)
20     {
21         for (int i=1; i<top; ++i) for (int j=i+1; j<=top; ++j)        //暴力枚举 
22         {
23             bool flag=1; int x=pri[j]-pri[i],num=pri[j]+x;    //x是公差,flag=1表示符合 
24             for (int k=3; k<=n; ++k)
25             {
26                 if (num>m||f[num]==1) {flag=0; break;}
27                 num+=x;
28             }
29             if (!flag) continue;
30             anstop++; ans[anstop][0]=x; ans[anstop][1]=pri[i];    //符合的都装进ans数组中 
31             for (int k=2; k<=n; ++k) ans[anstop][k]=ans[anstop][k-1]+x;
32         }
33         if (!anstop) fail=1;
34         else
35         {
36             int maxx=0,maxi,max1=0;
37             for (int i=1; i<=anstop; ++i)    //按题目要求找到输出数列 
38                 if (ans[i][0]>maxx||(ans[i][0]==maxx&&ans[i][1]>max1))
39                 {
40                     maxx=ans[i][0];
41                     max1=ans[i][1];
42                     maxi=i;
43                 }
44             printf("%d",ans[maxi][1]);
45             for (int i=2; i<=n; ++i) printf(" %d",ans[maxi][i]);
46         }
47     }
48     int maxpri;        //区间内最大素数 
49     for (int i=m; i>=2; --i) if (!f[i]) {maxpri=i; break;}
50     if (n==2)
51     {
52         if (m>2) printf("2 %d",maxpri);
53         else fail=1;
54     }
55     if (n==1) fail=1;
56     if (fail) printf("%d",maxpri);
57     return 0;
58 }

【7-2 Lab Access Scheduling】

将时间封装到结构体内
并按开始时间为第一关键字,结束时间为第二关键字排序

排序完之后用动态规划求解
f[i]表示前i个数中以第i个结尾的最多通过的申请
那么更新f[i]时只需扫一遍前面的f[1]~f[i-1]看是否能接在他们后面即可

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 using namespace std;
 6 
 7 const int N=2010;
 8 int n;
 9 struct node1{int h,m,s;};    //node1封装时间 
10 struct node2{node1 a,b;}a[N];    //a[i]表示每个申请,将每个申请的两个时间封装 
11 char s[100];
12 int f[N];
13 
14 inline bool cmp1(node1 x,node1 y)    //x<=y时返回1 
15 {
16     if (y.h<x.h) return 0; if (y.h>x.h) return 1;
17     if (y.m<x.m) return 0; if (y.m>x.m) return 1;
18     if (y.s<x.s) return 0; if (y.s>x.s) return 1;
19     return 1;
20 }
21 inline bool cmp3(node1 x,node1 y)    //当且仅当x=y时返回1 
22 {
23     if (y.h<x.h) return 0; if (y.h>x.h) return 0;
24     if (y.m<x.m) return 0; if (y.m>x.m) return 0;
25     if (y.s<x.s) return 0; if (y.s>x.s) return 0;
26     return 1;
27 }
28 inline bool cmp2(node2 x,node2 y)    //sort函数的参数 
29 {
30     if (!cmp1(x.a,y.a)) return 0;
31     if (cmp3(x.a,y.a)) return cmp1(x.b,y.b);
32     else return 1;        //此函数判断x和y的先后顺序,返回1则将x放在前面 
33 }
34 int main()
35 {
36     scanf("%d",&n);
37     for (int i=1; i<=n; ++i)
38     {
39         scanf("%s",&s);
40         a[i].a.h=(s[0]-48)*10+s[1]-48;
41         a[i].a.m=(s[3]-48)*10+s[4]-48;
42         a[i].a.s=(s[6]-48)*10+s[7]-48;
43         scanf("%s",&s);
44         a[i].b.h=(s[0]-48)*10+s[1]-48;
45         a[i].b.m=(s[3]-48)*10+s[4]-48;
46         a[i].b.s=(s[6]-48)*10+s[7]-48;
47     }
48     sort(a+1,a+n+1,cmp2);    //排序 
49     f[1]=1;
50     for (int i=2; i<=n; ++i)
51     {
52         f[i]=1;
53         for (int j=1; j<i; ++j) if (cmp1(a[j].b,a[i].a)) f[i]=max(f[i],f[j]+1);
54     }
55     printf("%d",f[n]);
56     return 0;
57 }

【7-3 Structure of Max-Heap】

按顺序建大根堆,读入询问并输出

由堆的性质可知:
1、根节点下标为1
2、左儿子下标+1=右儿子下标
3、左右儿子下标/2=父亲下标
4、左儿子下标为奇数,右儿子下标为偶数

设xpos为x在堆中的位置(下标),ypos同理
各种询问的判断方式如下:
①xpos==1
②xpos是偶数 && ypos是奇数 && xpos+1==ypos(默认xpos<ypos)
③xpos==ypos/2
④xpos/2==ypos && xpos为偶数
⑤xpos/2==ypos && xpos为奇数

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 const int N=1010;
 7 int n,m,a[N];
 8 int h[N<<1],top;
 9 char s[N];
10 
11 int x,y,xpos,ypos=-1;
12 
13 inline int find(int x)    //返回值x在堆中的位置,找不到则返回-1 
14 {
15     for (int i=1; i<=n; ++i) if (h[i]==x) return i;
16     return -1;
17 }
18 inline void pushup(int x)
19 {
20     while (x>1)
21     {
22         int y=x>>1;
23         if (h[y]<h[x]) {swap(h[y],h[x]); x=y;}
24         else break;
25     }
26 }
27 int main()
28 {
29     scanf("%d%d",&n,&m);
30     for (int i=1; i<=n; ++i)
31     {
32         scanf("%d",&a[i]);
33         h[++top]=a[i]; pushup(top);    //建堆 
34     }
35     for (int k=1; k<=m; ++k)
36     {
37         scanf("%d%s",&x,&s); xpos=find(x);    //读入x和第一个字符串 
38         if (s[0]=='a')    //开头为a表示是第二种询问 
39         {
40             scanf("%d",&y); scanf("%s",&s); scanf("%s",&s);//注意要将多余的两个字符串读入以防影响后续读入 
41             ypos=find(y); if (xpos>ypos) swap(xpos,ypos); 
42             if (xpos%2==0&&ypos%2==1&&xpos+1==ypos) printf("1"); else printf("0");
43             continue;
44         }
45         scanf("%s",&s); scanf("%s",&s);
46         if (s[0]=='r'&&s[1]=='o')//前两个字符为ro表示是第一种询问 
47         {
48             if (xpos==1) printf("1"); else printf("0");
49             continue;
50         }
51         if (s[0]=='p')//第一个字符为p表示是第三种询问 
52         {
53             scanf("%s",&s); scanf("%d",&y); ypos=find(y);
54             if (xpos==ypos/2) printf("1"); else printf("0");
55             continue;
56         }
57         if (s[0]=='l')//第一个字符为l表示是第四种询问 
58         {
59             scanf("%s",&s); scanf("%s",&s); scanf("%d",&y); ypos=find(y);
60             if (xpos/2==ypos&&xpos%2==0) printf("1"); else printf("0");
61             continue;
62         }    //剩下的即为第五种询问 
63         scanf("%s",&s); scanf("%s",&s); scanf("%d",&y); ypos=find(y);
64         if (xpos/2==ypos&&xpos%2==1) printf("1"); else printf("0");
65     }
66     return 0;
67 }

 【7-4 Recycling of Shared Bicycles】

邻接矩阵存图
以每个点为起点用SPFA算法跑单源最短路

按题意以0为起点每次去一个距离最短且未标记的点,并记录下来
第一行便输出记录下来的顺序
若并不是所有点都互相联通则最后还有点未标记,
这些未标记的点即为以0为起点走不到的点

最后注意:
1、达不到的距离我们用INF(一个极大数)表示,因为不知道联通两点的最短距离的上限会是多少,
所以我就无脑开long long来使INF可以取到很大的数
2、SPFA我没有用循环队列,所以我就把队列的数组q开的很大

 1 #include<cstdio>
 2 #define LL long long
 3 using namespace std;
 4 
 5 const LL N=250,INF=2e11;
 6 LL n,m,a[N][N];
 7 LL ans[N],top,s;
 8 LL dis[N][N],h,t,q[10000100];
 9 LL ansdis=0;
10 bool f[N];
11 
12 int main()
13 {
14     scanf("%lld%lld",&n,&m);
15     for (int i=0; i<=n; ++i) for (int j=0; j<=n; ++j) a[i][j]=INF;
16     for (int i=1; i<=m; ++i)
17     {
18         LL x,y,z; scanf("%lld%lld%lld",&x,&y,&z);
19         if (z<a[x][y]) a[x][y]=z;    //防重边 
20         if (z<a[y][x]) a[y][x]=z;
21     }
22     for (int l=0; l<=n; ++l)
23     {
24         for (int i=0; i<=n; ++i) dis[l][i]=INF;    //dis[i][j]表示i到j的最短路 
25         h=0; t=1; q[t]=l; dis[l][l]=0;
26         while (h<t)        //SPFA
27         {
28             h++;
29             for (int i=0; i<=n; ++i)
30                 if (a[q[h]][i]+dis[l][q[h]]<dis[l][i])
31                 {
32                     dis[l][i]=a[q[h]][i]+dis[l][q[h]];
33                     q[++t]=i;
34                 }
35         }
36     }
37     top=1; f[0]=1; s=0; bool flag=1;
38     for (int l=1; l<=n; ++l)
39     {
40         LL minn=INF,minpos;
41         for (int i=0; i<=n; ++i)
42             if (f[i]==0&&dis[s][i]<minn) {minn=dis[s][i]; minpos=i;}
43         if (minn==INF) {flag=0; break;}
44         ans[++top]=minpos; ansdis+=minn; f[minpos]=1; s=minpos;
45     }
46     printf("0");    //第一个点必是0
47     for (int i=2; i<=top; ++i) printf(" %lld",ans[i]);    //这样输出不会有行末空格 
48     printf("\n");
49     if (flag) printf("%lld",ansdis);
50     else
51     {
52         top=0;
53         for (int i=1; i<=n; ++i) if (!f[i]) ans[++top]=i;
54         for (int i=1; i<=top; ++i)
55         {
56             printf("%lld",ans[i]);
57             if (i<top) printf(" ");
58         }
59     }
60     return 0;
61 }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM