【题目自解】北京大学2017计算机学科夏令营上机考试
A:判决素数个数 (NOI 1.13编程基础之综合应用)
解题思路
两个坑,一个是x,y大小关系不确定,要写一个交换;一个是取值范围可以到100000,因此i*i到了十位数量级,在int表示中是负数(虽然我觉得没到int限制范围啊,但是测试结果确实是这样),这时候访问数组会报错。
如果继续用i*i,语句应该改为
for (int j = i * i; j <= N && j>0; j += i) mark[j] = 1;
AC代码(2*i版本)
#include<cstdio> #include<cstring> const int N = 100000; int mark[N + 5] = { 0 }; int num = 0; void Prime() { mark[1] = 1; for (int i = 2; i <= N; i++) { if (mark[i] == 1)continue; for (int j = 2 * i; j <= N; j += i) mark[j] = 1; } } int main() { int x, y; scanf("%d%d", &x, &y); if (x > y) { int t = y; y = x; x = t; } Prime(); for (int i = x; i <= y; i++) { if (mark[i] == 0)num++; } printf("%d", num); return 0; }
B:编码字符串
解题思路
简单题,直接做就行了。tolower的头文件是cctype,string里面也有。更简单的做法是边判断边输出。
解题代码
#include<cstdio> #include<cstring> #include<cctype> char s[1005]; char c[1005];//存储字符 int n[1005];//存储每个字符的数量 int cnt = 0;//分割段数-1 int main() { scanf("%s", s); int len = strlen(s); for (int i = 0; i < len; i++)s[i] = tolower(s[i]); c[0] = s[0];//初始化 memset(n, 0, sizeof(n)); n[0] = 1; for (int i = 1; i < len; i++) { if (s[i] == c[cnt])n[cnt]++; else { cnt++; c[cnt] = s[i]; n[cnt]++; } } for (int i = 0; i <= cnt; i++) { printf("(%c,%d)", c[i], n[i]); } return 0; }
#include <cstdio> #include <cstring> using namespace std; int main() { char buf[1001]; scanf("%s",buf); int len=strlen(buf); int i; for(i=0;i<len;i++){ if(buf[i]>='A'&&buf[i]<='Z'){ buf[i]+=32; } } i=0; char tmp; int cnt; while(i<len){ tmp=buf[i]; cnt=0; while(buf[i]==tmp){ i++; cnt++; } printf("(%c,%d)",tmp,cnt); } printf(" "); return 0; }
C:岛屿周长
解题思路
简单题,深搜遍历上下左右的点,如果是海或者是边界,那么周长++。
AC代码
#include<cstdio> #include<cstring> int map[105][105]; int mark[105][105] = { 0 }; int n, m; int len = 0; int dx[4] = { 0,1,0,-1 }; int dy[4] = { 1,0,-1,0 }; bool valid(int x,int y) { return(x >= 0 && x < n && y >= 0 && y < m); } void DFS(int x,int y) { mark[x][y] = 1; for (int i = 0; i < 4; i++) { int newx = x + dx[i]; int newy = y + dy[i]; if (valid(newx, newy)) { if (mark[newx][newy] == 0) DFS(newx, newy); } else len++; } } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) scanf("%d", &map[i][j]); } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (mark[i][j] == 1 || map[i][j] == 0)continue; DFS(i, j); } } printf("%d", len); return 0; }
E:怪盗基德的滑翔翼
解题思路
简单题,因为可以任选一个方向,所以是正反都要做一次最长不上升子序列,等价于正序找最长不上升子序列和最长不下降子序列,然后取较大值。
AC代码
#include<cstdio> const int N = 105; int a[N];//记录原序列 int dp[N];//dp[i]表示包括第i位之前序列的最长上升子序列长度 int len;//原序列长度 int LIS() { int tmp = 1;//返回值,表示整个序列的LIS值 for (int i = 1; i <= len; i++) { dp[i] = 1;//都初始化为1,方便后面直接比较 for (int j = 1; j < i; j++) { if (a[j] <= a[i] && dp[j] + 1 > dp[i]) dp[i] = dp[j] + 1; } if (dp[i] > tmp) tmp = dp[i]; } return tmp; } int RLIS() { int tmp = 1;//返回值,表示整个序列的RLIS值 for (int i = 1; i <= len; i++) { dp[i] = 1;//都初始化为1,方便后面直接比较 for (int j = 1; j < i; j++) { if (a[j] >= a[i] && dp[j] + 1 > dp[i]) dp[i] = dp[j] + 1; } if (dp[i] > tmp) tmp = dp[i]; } return tmp; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%d", &len); for (int i = 1; i <= len; i++)scanf("%d", &a[i]); int a1 = LIS(); int a2 = RLIS(); int ans = a1 > a2 ? a1 : a2; printf("%d ", ans); } return 0; }
G:实现堆结构
解题思路
使用优先队列。
AC代码
#include <iostream> #include <cstdio> #include <vector> #include <queue> #include <algorithm> using namespace std; priority_queue<int, vector<int>, greater<int> > q; // 小堆顶结构 int main() { int t; scanf("%d", &t); for(int i=0; i<t; i++) { int n, type; scanf("%d", &n); for(int j=0; j<n; j++) { scanf("%d", &type); if(type == 1) { int u; scanf("%d", &u); q.push(u); } if(type == 2) { printf("%d ", q.top()); q.pop(); } } } return 0; }
D:Safecracker
解题思路
可以用五层循环,也可以用dfs。
AC代码(五层循环暴搜解法)
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int toInt(char ch) { return ch - 'A' + 1; } int target; char a[15]; int main() { while (scanf("%d%s", &target, a) && (target != 0 || strcmp(a, "END") != 0)) { sort(a, a + strlen(a)); int sum; int flag = 0; string str; for (int i = 0; a[i]; i++) { for (int j = 0; a[j]; j++) { for (int k = 0; a[k]; k++) { for (int l = 0; a[l]; l++) { for (int m = 0; a[m]; m++) { if (i != j && i != k && i != l && i != m && j != k && j != l && j != m && k != l && k != m && l != m) { sum = toInt(a[i]) - toInt(a[j]) * toInt(a[j]) + toInt(a[k]) *toInt(a[k]) * toInt(a[k]) - toInt(a[l]) *toInt(a[l]) * toInt(a[l]) *toInt(a[l]) + toInt(a[m]) * toInt(a[m]) *toInt(a[m]) *toInt(a[m]) * toInt(a[m]); if (sum == target) { flag = 1; str = ""; str = str + a[i] + a[j] + a[k] + a[l] + a[m]; break; } } } } } } } if (flag == 1) { printf("%s ", str.c_str()); } else printf("no solution "); } return 0; }
AC代码(DFS解法)
#include <iostream> #include <cstring> using namespace std; int n; int len; char s[15];//存放原字符串 int vis[15];//深搜访问标记 int t[5];//存放最终字符串 int p[5];//转换后的数字 void check()//更新为最大字典序 { for (int i = 0; i < 5; i++) { if (p[i] > t[i]) { for (int j = 0; j < 5; j++) { t[j] = p[j]; } break; } if (p[i] < t[i]) { break; } } } void dfs(int cur) { if (cur == 5) { if (n == p[0] - p[1] * p[1] + p[2] * p[2] * p[2] - p[3] * p[3] * p[3] * p[3] + p[4] * p[4] * p[4] * p[4] * p[4]) { check(); } } else { for (int i = 0; i < len; i++)//逐元素向前推进进行深搜 { if (!vis[i]) { vis[i] = 1; p[cur] = s[i] - 'A' + 1; dfs(cur + 1); vis[i] = 0;//回溯 } } } } int main() { while (true) { cin >> n >> s; if (n == 0) { return 0; } len = strlen(s); memset(vis, 0, sizeof(vis)); memset(t, 0, sizeof(t)); memset(p, 0, sizeof(p)); dfs(0); if (t[0] == 0) { cout << "no solution" << endl; } else { for (int i = 0; i < 5; i++) { cout << (char)(t[i] + 'A' - 1); } cout << endl; } } return 0; }