今年上半学期的校队选拔题目,是从poj上抽的几道题。为了照顾尚未学习算法和数据结构的同学,同时结合前几次培训的内容,考察了模拟,搜索和数学题目,总体来说,题目没有太大的难度,但两道搜索较为繁杂,需要考虑一些细节问题,同时也要求良好的编写代码能力。编写代码能力是ACM学习的基础,希望各位同学能多花时间写一写题,加强编写代码的能力。若对题解有疑问,可在下方评论或直接与我联系。
【POJ2739】Sum of Consecutive Prime Numbers
对给定的一个数k,寻找可以被连续素数之和组成的方案数,由于在[1,10000]区间内的素数只有小于1300个,可以直接用素数筛找出所有素数后,通过枚举所有方案,得到答案。
#include<iostream> #include<cstdio> #include<map> #include<set> #include<vector> #include<stack> #include<queue> #include<string> #include<cstring> #include<sstream> #include<algorithm> #include<cmath> #define INF 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) using namespace std; const int maxn = 10000; int prime[maxn + 10],m = 0; int cou[maxn + 10]; bool vis[maxn + 10]; int init() { for (int i = 2;i <= maxn; i++) if (!vis[i]) { prime[++m] = i + prime[m-1]; for (int j = i+i;j <= maxn; j += i) vis[j] = true; } for (int i = 1;i <= m; i++) for (int j = i-1;j >= 0; j--) if (prime[i]-prime[j] <= maxn) cou[prime[i]-prime[j]]++; else break; } int main() { init(); int n; while (scanf("%d",&n) != EOF) { if (!n) break; printf("%d\n",cou[n]); } return 0; }
【POJ1573】Robot Motion
模拟题,求机器人在题中给出地图中行走的步数,根据题目中给定的规则执行即可,注意字符的读取。
#include<iostream> #include<cstdio> #include<map> #include<set> #include<vector> #include<stack> #include<queue> #include<string> #include<cstring> #include<sstream> #include<algorithm> #include<cmath> #define INF 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) using namespace std; const int mov[4][2] = {-1,0,1,0,0,1,0,-1}; int n,m,k; char a[1010][1010]; int vis[1010][1010]; map<char,int> dir; bool is_sta(int x,int y) { if (x < 1 || x > n || y < 1 || y > m) return false; return true; } int main() { dir['N'] = 0;dir['S'] = 1;dir['E'] = 2;dir['W'] = 3; while (scanf("%d%d%d%*c",&n,&m,&k) != EOF) { memset(vis,0,sizeof(vis)); if (n == 0 && m == 0 && k == 0) break; for (int i = 1;i <= n; i++) { for (int j = 1;j <= m; j++) scanf("%c",&a[i][j]); scanf("%*c"); } int x = 1,y = k,cou = 1; int s1 = 0,s2 = 0; vis[x][y] = 1; while (true) { int d = dir[a[x][y]]; x += mov[d][0]; y += mov[d][1]; //cout << x <<":" << y << endl; if (!is_sta(x,y)) { s1 = cou; break; } if (vis[x][y]) { s1 = vis[x][y] - 1; s2 = cou - vis[x][y] + 1; break; } vis[x][y] = ++cou; } if (s2) printf("%d step(s) before a loop of %d step(s)\n",s1,s2); else printf("%d step(s) to exit\n",s1); } return 0; }
【POJ2109】Power of Cryptography
给出n,p,求使k^n = p的k,之前我做这道是用对数做的,后来发现直接开方就可以OTZ,所以其实这才是最水的一道题。
#include<iostream> #include<cstdio> #include<map> #include<set> #include<vector> #include<stack> #include<queue> #include<string> #include<cstring> #include<sstream> #include<algorithm> #include<cmath> #define INF 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) using namespace std; int main() { double n,p; while (scanf("%lf%lf",&n,&p) != EOF) { double k = log2(p)/n; int ans = pow(2,k) + eps; //像这样也可以过OTZ // int ans = (double)pow(p,1/n) + eps; printf("%d\n",ans); } return 0; }
【POJ3009】Power of Cryptography
DFS深度优先搜索,因为数据范围很小,不用加优化也可以通过,枚举每次滚动的方向进行搜索。值得注意的一点:本题中是先给列数,再给的行数。
#include<iostream> #include<cstdio> #include<map> #include<set> #include<vector> #include<stack> #include<queue> #include<string> #include<cstring> #include<sstream> #include<algorithm> #include<cmath> #define INF 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) using namespace std; const int mov[4][2] = {1,0,-1,0,0,1,0,-1}; int n,m,ans; int a[30][30]; bool is_sta(int x,int y) { if (x < 1 || x > n || y < 1 || y > m) return false; return true; } void dfs(int x,int y,int step) { if (step > 10) return; for (int i = 0;i < 4; i++) { if (a[x+mov[i][0]][y+mov[i][1]] == 1) continue; int nx = x,ny = y; while (is_sta(nx,ny) && a[nx][ny] != 3 && a[nx][ny] != 1) { nx += mov[i][0]; ny += mov[i][1]; } if (!is_sta(nx,ny)) continue; if (a[nx][ny] == 3) { if (ans == -1) ans = step; else ans = min(ans,step); } if (a[nx][ny] == 1) { a[nx][ny] = 0; dfs(nx-mov[i][0],ny-mov[i][1],step+1); a[nx][ny] = 1; } } } int main() { while (scanf("%d%d",&m,&n) != EOF) { memset(a,0,sizeof(a)); if (n == 0 && m == 0) break; int x,y; for (int i = 1;i <= n; i++) for (int j = 1;j <= m; j++) { scanf("%d",&a[i][j]); if (a[i][j] == 2) {x = i;y = j;} } ans = -1; dfs(x,y,1); printf("%d\n",ans); } return 0; }
【POJ3414】Pots
BFS宽度优先搜索,可视为无权图最短路问题,用BFS解决,在每轮中枚举六种操作,第一次找到的解即为最优解,之后递归输出方案。
#include<iostream> #include<cstdio> #include<map> #include<set> #include<vector> #include<stack> #include<queue> #include<string> #include<cstring> #include<sstream> #include<algorithm> #include<cmath> #define INF 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) using namespace std; struct point { int x,y,f,act; }; point line[10100]; bool vis[110][110]; void print(int k,int cnt) { if (line[k].f) print(line[k].f,cnt+1); else printf("%d\n",cnt); if (line[k].act == 1) puts("FILL(1)"); if (line[k].act == 2) puts("FILL(2)"); if (line[k].act == 3) puts("DROP(1)"); if (line[k].act == 4) puts("DROP(2)"); if (line[k].act == 5) puts("POUR(1,2)"); if (line[k].act == 6) puts("POUR(2,1)"); } int main() { int a,b,c; while (scanf("%d%d%d",&a,&b,&c) != EOF) { memset(vis,0,sizeof(vis)); int p1 = 1,p2 = 1; line[p2++] = (point){0,0,0}; vis[0][0] = true; bool ans = false; while (p1 < p2) { point p = line[p1]; if (p.x == c || p.y == c) { print(p1,0); ans = true; break; } if (!vis[a][p.y]) { line[p2++] = (point){a,p.y,p1,1}; vis[a][p.y] = true; } if (!vis[p.x][b]) { line[p2++] = (point){p.x,b,p1,2}; vis[p.x][b] = true; } if (!vis[0][p.y]) { line[p2++] = (point){0,p.y,p1,3}; vis[0][p.y] = true; } if (!vis[p.x][0]) { line[p2++] = (point){p.x,0,p1,4}; vis[p.x][0] = true; } int x = p.x,y = p.y; if (p.x + p.y > b) x = p.x+p.y-b,y = b; else x = 0,y = p.x+p.y; if (!vis[x][y]) { line[p2++] = (point){x,y,p1,5}; vis[x][y] = true; } x = p.x,y = p.y; if (p.x + p.y > a) x = a,y = p.x+p.y-a; else x = p.x+p.y,y = 0; if (!vis[x][y]) { line[p2++] = (point){x,y,p1,6}; vis[x][y] = true; } p1++; } if (!ans) puts("impossible"); } return 0; }
【POJ1850】Code
递推,计算给出的字符串是第几个递增字符串,f[i][j]表示最高位是第i位,第i位为j(0 <= j < 26)的递增字符串个数,递推式为
f[i][j] = sum(f[i-1][k](1 <= k < 26))(j = 0)
f[i][j] = f[i][j-1] - f[i][j] (0 < j < 26)
#include<iostream> #include<cstdio> #include<map> #include<set> #include<vector> #include<stack> #include<queue> #include<string> #include<cstring> #include<sstream> #include<algorithm> #include<cmath> #define INF 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) using namespace std; string st; int f[20][30]; void init() { for (int i = 0;i < 26; i++) f[1][i] = 1; for (int i = 2;i <= 10; i++) { for (int j = 1;j < 26; j++) f[i][0] += f[i-1][j]; for (int j = 1;j <= 26-i; j++) f[i][j] = f[i][j-1] - f[i-1][j]; } } int main() { init(); while (cin >> st) { int ans = 0,n = st.length(); for (int i = 1;i < n; i++) { if (st[i] < st[i-1]) { ans = -1; break; } } if (ans == -1) { printf("%d\n",0); break; } for (int i = n;i > 0; i--) { for (int j = 0;j <= st[n-i]-'a'; j++) ans += f[i][j]; } printf("%d\n",ans); } return 0; }
到此,本学期与ACM有关的活动已经全部结束,回顾月赛,新秀杯和这次的选拔赛,不知道大家在ACM中收获了什么?如果能在coding感受到快乐的话,那是再好不过了。时间已经临近期末,也请大家好好复习,祝大家在期末考试中能取得好成绩!另外,校集训队会在寒假中组织培训,主要内容为动态规划(DP)及图论算法。
我们寒假再见!
PS:天气太冷我已经冻感冒了,大家也注意身体(吸鼻涕,总之早点睡觉多喝热水总是没错的。