【题解】SWJTU2015.12校队选拔题解

今年上半学期的校队选拔题目,是从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:天气太冷我已经冻感冒了,大家也注意身体(吸鼻涕,总之早点睡觉多喝热水总是没错的。

你可能感兴趣的:(ACM,poj)