题解PAT团体程序设计天梯赛 - 模拟赛
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解PAT团体程序设计天梯赛 - 模拟赛相关的知识,希望对你有一定的参考价值。
由于本人愚笨,最后一题实在无力AC,于是只有前14题的题解Orz
总的来说,这次模拟赛的题目不算难,前14题基本上一眼就有思路,但是某些题写起来确实不太容易,编码复杂度有点高~
L1-1 N个数求和
设计一个分数类,重载加法运算符,注意要约分,用欧几里得算法求个最大公约数即可。
1 #include <cstdio> 2 3 long long abs(long long x) 4 { 5 return x < 0 ? -x : x; 6 } 7 8 long long gcd(long long a, long long b) 9 { 10 if (b == 0) 11 return a; 12 else if (a > b) 13 return gcd(b, a % b); 14 else 15 return gcd(a, b % a); 16 } 17 18 struct FS 19 { 20 long long fz, fm; 21 FS(long long _fz = 0, long long _fm = 1) 22 { 23 fz = _fz; 24 fm = _fm; 25 if (fz & fm) 26 { 27 long long g = gcd(abs(fz), abs(fm)); 28 fz /= g; 29 fm /= g; 30 } 31 } 32 friend FS operator+ (const FS& a, const FS& b) 33 { 34 FS ans; 35 long long lcm = a.fm / gcd(abs(a.fm), abs(b.fm)) * b.fm; 36 ans.fz = a.fz * (lcm / a.fm) + b.fz * (lcm / b.fm); 37 ans.fm = lcm; 38 if (ans.fz && ans.fm) 39 { 40 long long g = gcd(abs(ans.fz), abs(ans.fm)); 41 ans.fz /= g; 42 ans.fm /= g; 43 } 44 return ans; 45 } 46 }; 47 48 int main() 49 { 50 int n; 51 scanf("%d", &n); 52 FS ans; 53 char buf[64]; 54 while (n--) 55 { 56 scanf("%s", buf); 57 long long fz, fm; 58 sscanf(buf, "%lld/%lld", &fz, &fm); 59 ans = ans + FS(fz, fm); 60 } 61 if (ans.fz == 0) 62 printf("0"); 63 else if (abs(ans.fz) < abs(ans.fm)) 64 printf("%lld/%lld", ans.fz, ans.fm); 65 else 66 { 67 if (ans.fz % ans.fm == 0) 68 printf("%lld", ans.fz / ans.fm); 69 else 70 printf("%lld %lld/%lld", ans.fz / ans.fm, ans.fz % ans.fm, ans.fm); 71 } 72 return 0; 73 }
L1-2 比较大小
太水了,不解释,直接sort一下。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 int main() 6 { 7 int a[3]; 8 scanf("%d%d%d", a, a + 1, a + 2); 9 sort(a, a + 3); 10 printf("%d->%d->%d", a[0], a[1], a[2]); 11 return 0; 12 }
L1-3 A-B
用一个bool数组记录第二个字符串中出现的字符,然后遍历第一个字符串,检测是否在第二个字符串中出现过。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 char s1[10010]; 6 char s2[10010]; 7 bool vis[128]; 8 9 int main() 10 { 11 gets(s1); 12 gets(s2); 13 int idx = -1; 14 while (s2[++idx]) 15 vis[s2[idx]] = true; 16 idx = -1; 17 while (s1[++idx]) 18 if (!vis[s1[idx]]) 19 putchar(s1[idx]); 20 return 0; 21 }
L1-4 计算指数
太水了,直接左移位。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 int main() 6 { 7 int n; 8 scanf("%d", &n); 9 printf("%d^%d = %d", 2, n, 1 << n); 10 return 0; 11 }
L1-5 计算阶乘和
太水了,求阶乘累加。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 int main() 6 { 7 int n; 8 scanf("%d", &n); 9 int sum = 0; 10 int fact = 1; 11 for (int i = 1; i <= n; i++) 12 sum += fact *= i; 13 printf("%d", sum); 14 return 0; 15 }
L1-6 简单题
hello world同级别的题。
1 #include <cstdio> 2 int main() 3 { 4 printf("This is a simple problem."); 5 return 0; 6 }
L1-7 跟奥巴马一起画方块
双重循环。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 int main() 6 { 7 int n; 8 char c[2]; 9 scanf("%d%s", &n, c); 10 for (int i = 0; i < (n + 1) / 2; i++, puts("")) 11 for (int j = 0; j < n; j++) 12 putchar(c[0]); 13 return 0; 14 }
L1-8 查验身份证
按规则模拟就好了,注意判断前17位有无非数字。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 int wei[] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2}; 6 int rlt[] = {1,0,-1,9,8,7,6,5,4,3,2}; 7 8 bool check(char *s) 9 { 10 int sum = 0; 11 for (int i = 0; i < 17; i++) 12 { 13 if (!isdigit(s[i])) 14 return false; 15 sum += (s[i] - ‘0‘) * wei[i]; 16 } 17 sum %= 11; 18 if (rlt[sum] == -1) 19 return s[17] == ‘X‘; 20 else 21 return s[17] - ‘0‘ == rlt[sum]; 22 } 23 24 int main() 25 { 26 int n; 27 char s[20]; 28 scanf("%d", &n); 29 bool allpass = true; 30 while (n--) 31 { 32 scanf("%s", s); 33 if (!check(s)) 34 { 35 puts(s); 36 allpass = false; 37 } 38 } 39 if (allpass) 40 puts("All passed"); 41 return 0; 42 }
L2-1 集合相似度
排序后,对于每个询问二分好像会超时一组数据。那么我们可以把那些数字离散化&去重之后,用hash思想来做,O(M)复杂度处理每个查询。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 int sorted[500010]; 6 int sset[60][10010]; 7 bool vis[500010]; 8 int rec[20010]; 9 10 int main() 11 { 12 int n; 13 scanf("%d", &n); 14 int tot = 0; 15 for (int i = 0; i < n; i++) 16 { 17 scanf("%d", &sset[i][0]); 18 for (int j = 1; j <= sset[i][0]; j++) 19 scanf("%d", &sset[i][j]), sorted[tot++] = sset[i][j]; 20 sort(sset[i] + 1, sset[i] + 1 + sset[i][0]); 21 sset[i][0] = unique(sset[i] + 1, sset[i] + 1 + sset[i][0]) - sset[i] - 1; 22 } 23 sort(sorted, sorted + tot); 24 tot = unique(sorted, sorted + tot) - sorted; 25 for (int i = 0; i < n; i++) 26 for (int j = 1; j <= sset[i][0]; j++) 27 sset[i][j] = lower_bound(sorted, sorted + tot, sset[i][j]) - sorted; 28 int k; 29 scanf("%d", &k); 30 while (k--) 31 { 32 int a, b; 33 scanf("%d%d", &a, &b); 34 a--, b--; 35 int nc = 0, nt = 0; 36 int reccnt = 0; 37 for (int i = 1; i <= sset[a][0]; i++) 38 vis[sset[a][i]] = true, rec[reccnt++] = sset[a][i]; 39 nt = sset[a][0]; 40 for (int i = 1; i <= sset[b][0]; i++) 41 { 42 rec[reccnt++] = sset[b][i]; 43 if (vis[sset[b][i]]) 44 nc++; 45 else 46 nt++; 47 } 48 for (int i = 0; i < reccnt; i++) 49 vis[rec[i]] = false; 50 printf("%.2f%\n", 1.0 * nc / nt * 100); 51 } 52 return 0; 53 }
L2-2 树的遍历
后序序列最后一个是根节点,用那个根节点把中序序列分开,然后递归建树,最后再宽搜一下。
1 #include <cstdio> 2 #include <vector> 3 #include <queue> 4 #include <algorithm> 5 using namespace std; 6 7 vector<int> tree[40]; 8 int n; 9 int hx[40]; 10 int zx[40]; 11 12 int deal(int lz, int rz, int lh, int rh) 13 { 14 if (lz > rz || lh > rh) 15 return -1; 16 int root = hx[rh]; 17 int pos = find(zx + lz, zx + rz + 1, root) - zx; 18 int cnt = pos - lz; 19 tree[root].push_back(deal(lz, pos - 1, lh, lh + cnt - 1)); 20 tree[root].push_back(deal(pos + 1, rz, lh + cnt, rh - 1)); 21 return root; 22 } 23 24 int main() 25 { 26 scanf("%d", &n); 27 for (int i = 0; i < n; i++) 28 scanf("%d", hx + i); 29 for (int i = 0; i < n; i++) 30 scanf("%d", zx + i); 31 int root = deal(0, n - 1, 0, n - 1); 32 queue<int> q; 33 q.push(root); 34 bool flag = false; 35 while (!q.empty()) 36 { 37 int cur = q.front(); 38 q.pop(); 39 if (flag) 40 printf(" %d", cur); 41 else 42 printf("%d", cur), flag = true; 43 if (tree[cur][0] != -1) 44 q.push(tree[cur][0]); 45 if (tree[cur][1] != -1) 46 q.push(tree[cur][1]); 47 } 48 return 0; 49 }
L2-3 家庭房产
思路很简单,就是普通的并查集,但是代码不太好写哦~
#include <cstdio> #include <algorithm> using namespace std; struct Node { int parent; int ts, mj; }; struct Result { int minid; int siz; int ts, mj; friend bool operator< (const Result& a, const Result& b) { if (1LL * a.mj * b.siz == 1LL * b.mj * a.siz) return a.minid < b.minid; return 1LL * a.mj * b.siz > 1LL * b.mj * a.siz; } }; Node node[10010]; Result rlt[10010]; int uf_find(int x) { if (node[x].parent == x) return x; return node[x].parent = uf_find(node[x].parent); } void uf_union(int x, int y) { x = uf_find(x); y = uf_find(y); if (x != y) node[x].parent = y; } int main() { int n; scanf("%d", &n); for (int i = 0; i < 10000; i++) node[i].parent = i, rlt[i].minid = 1000000; while (n--) { int id, f, m, k, hz; scanf("%d%d%d%d", &id, &f, &m, &k); if (f != -1) uf_union(f, id); if (m != -1) uf_union(m, id); for (int i = 0; i < k; i++) { scanf("%d", &hz); uf_union(hz, id); } scanf("%d%d", &node[id].ts, &node[id].mj); } for (int i = 0; i < 10000; i++) { int x = uf_find(i); rlt[x].minid = min(rlt[x].minid, i); rlt[x].ts += node[i].ts; rlt[x].mj += node[i].mj; rlt[x].siz++; } sort(rlt, rlt + 10000); int cnt = 0; for (int i = 0; i < 10000; i++) { if (rlt[i].mj != 0) cnt++; else break; } printf("%d\n", cnt); for (int i = 0; i < cnt; i++) { if (rlt[i].mj != 0) printf("%04d %d %.3f %.3f\n", rlt[i].minid, rlt[i].siz, 1.0 * rlt[i].ts / rlt[i].siz, 1.0 * rlt[i].mj / rlt[i].siz); } return 0; }
L2-4 最长对称子串
枚举回文中点,向两边扩展枚举。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 char s[1010]; 7 8 int main() 9 { 10 gets(s); 11 int len = strlen(s); 12 int ans = 0; 13 for (int i = 0; i < len; i++) 14 { 15 int l = i, r = i; 16 int curans = 0; 17 while (l >= 0 && r < len && s[l] == s[r]) 18 curans += 2, l--, r++; 19 ans = max(ans, curans - 1); 20 if (i < len - 1 && s[i] == s[i + 1]) 21 { 22 l = i; 23 r = l + 1; 24 curans = 0; 25 while (l >= 0 && r < len && s[l] == s[r]) 26 curans += 2, l--, r++; 27 ans = max(ans, curans); 28 } 29 } 30 printf("%d", ans); 31 return 0; 32 }
L3-1 肿瘤诊断
三维的图找连通块,道理和二维一样,注意这里只能宽搜。
1 #include <cstdio> 2 #include <queue> 3 using namespace std; 4 5 bool pic[61][1287][129]; 6 bool vis[61][1287][129]; 7 int dx[] = {1,-1,0,0,0,0}; 8 int dy[] = {0,0,-1,1,0,0}; 9 int dz[] = {0,0,0,0,1,-1}; 10 int m, n, l, t; 11 12 int bfs(int z, int x, int y) 13 { 14 queue<int> q; 15 q.push(z * (m * n) + x * n + y); 16 vis[z][x][y] = true; 17 int cnt = 0; 18 while (!q.empty()) 19 { 20 cnt++; 21 int cur = q.front(); 22 q.pop(); 23 z = cur / (m * n); 24 cur %= m * n; 25 x = cur / n; 26 y = cur % n; 27 for (int i = 0; i < 6; i++) 28 { 29 int zz = z + dz[i]; 30 int xx = x + dx[i]; 31 int yy = y + dy[i]; 32 if (zz < 0 || zz >= l) 33 continue; 34 if (xx < 0 || xx >= m) 35 continue; 36 if (yy < 0 || yy >= n) 37 continue; 38 if (pic[zz][xx][yy] && !vis[zz][xx][yy]) 39 { 40 vis[zz][xx][yy] = true; 41 q.push(zz * (m * n) + xx * n + yy); 42 } 43 } 44 } 45 return cnt; 46 } 47 48 int main() 49 { 50 scanf("%d%d%d%d", &m, &n, &l, &t); 51 for (int i = 0; i < l; i++) 52 for (int j = 0; j < m; j++) 53 for (int k = 0; k < n; k++) 54 { 55 int v; 56 scanf("%d", &v); 57 pic[i][j][k] = v == 1; 58 } 59 int ans = 0; 60 for (int i = 0; i < l; i++) 61 for (int j = 0; j < m; j++) 以上是关于题解PAT团体程序设计天梯赛 - 模拟赛的主要内容,如果未能解决你的问题,请参考以下文章