【題解】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