【解题报告】Codeforces Round #301 (Div. 2)

题目链接

A.Combination Lock(Codefoeces 540A)

思路

由于锁的齿轮的数量比较少,所以可以对每个齿轮,尝试向上拨或向下拨两种方法来更新最小转动次数。具体可以用模10下的加减法来实现。

代码


#include <bits/stdc++.h>
using namespace std;

int n, a, b, ans;
string s, t;

int main() {
    scanf("%d", &n);
    cin >> s >> t;
    ans = 0;
    for(int i = 0; i < n; i++) {
        a = (s[i] - t[i] + 10) % 10;
        b = (t[i] - s[i] + 10) % 10;
        ans += min(a, b);
    }
    printf("%d\n", ans);
    return 0;
}

B.School Marks(Codeforces 540B)

分析

可以从题目中抽取出主角分数的三个限制条件:

  • 每场考试的分数都在 1 p 分之间
  • 考试的分数至少以 y 作为中位数
  • 考试的总分不得超过 x

于是可以想到的一种可行的策略是:当考低分段(小于中位数)的分数的次数比较多的时候考 y 分,当考高分段(大于或等于中位数)的分数的次数比较多的时候考 1 分。这样就能够在满足前两种情况的前提下,拿到可能拿到的最低分。此时若能够满足第三种条件,那么就构造出了一种可行解。若不能满足第三种条件的话无论如何都不能构造出可行解了。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e3;
int n, p, k, x, y, low, high, mark, sum, ans[maxn];

int main() {
    cin >> n >> k >> p >> x >> y;
    low = high = sum = 0;
    for(int i = 0; i < k; i++) {
        cin >> mark;
        sum += mark;
        if(mark < y) low++;
        else high++;
    }
    for(int i = 0; i < n - k; i++) {
        if(low >= high) {
            ans[i] = y;
            sum += y;
            high++;
        }
        else {
            ans[i] = 1;
            sum++;
            low++;
        }
    }
    if(low < high && sum <= x) {
        for(int i = 0; i < n - k; i++) {
            printf("%d ", ans[i]);
        }
        puts("");
    }
    else puts("-1");
    return 0;
}

C.Ice Cave(Codeforces 540C)

思路

典型的路径寻找问题。用搜索来解决。注意如果用DFS来解决的话不用保护现场,因为被破坏的现场有“记忆”功能,能够减少很多枚举量。若保护现场则复杂度变成指数级别,提交会超时。

代码(DFS)

#include <bits/stdc++.h>
using namespace std;

const int maxn = 505;
char G[maxn][maxn];
int n, m, r1, c1, r2, c2;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};

bool dfs(int x, int y) {
    if(G[x][y] != '.') {
        return x == r2 && y == c2;
    }
    G[x][y] = 'X';
    for(int i = 0; i < 4; i++) {
        if(dfs(x + dx[i], y + dy[i])) {
            return true;
        }
    }
    return false;
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) {
        scanf("%s", G[i] + 1);
    }
    scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
    G[r1][c1] = '.';
    puts(dfs(r1, c1) ? "YES" : "NO");
    return 0;
}

代码(BFS)

#include <bits/stdc++.h>
using namespace std;

struct p {
    int x, y;
    p(int x, int y): x(x), y(y) {}
};

const int maxn = 505;
char G[maxn][maxn];
int n, m, x, y, a, b, r1, c1, r2, c2;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
queue <p> q;

bool bfs() {
    q.push(p(r1, c1));
    while(!q.empty()) {
        p node = q.front();
        q.pop();
        x = node.x, y = node.y;
        if(G[x][y] == 'X' && x == r2 && y == c2) {
            return true;
        }
        if(G[x][y] == 'X') continue;
        G[x][y] = 'X';
        for(int i = 0; i < 4; i++) {
            a = x + dx[i], b = y + dy[i];
            if(G[a][b] == '.' || a == r2 && b == c2) {
                q.push(p(a, b));
            }
        }
    }
    return false;
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) {
        scanf("%s", G[i] + 1);
    }
    scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
    G[r1][c1] = '.';
    puts(bfs() ? "YES" : "NO");
    return 0;
}

D.Bad Luck Island(Codeforces 540D)

思路

不好直接求解的概率问题通常都是用动态规划去做。本题的状态可以这样设计: (i,j,k) 表示目前岛上居住着的石头,剪刀和布的个数分别为 i,j,k 。如果我们用 d[i][j][k] 来表示状态 (i,j,k) 发生的概率的话,最终我们的答案就是求 d[0][0][k],d[0][j][0]d[i][0][0] 。初始状态(r, s, p)的概率为1。现尝试找状态转移方程。对于状态 (i,j,k) ,可以转移到这个状态的状态为 (i+1,j,k)(i,j+1,k)(i,j,k+1) 。发生转移的情况分别为石头与布相遇(石头减少),石头与剪刀相遇(剪刀减少)和剪刀与布相遇(布减少)。于是就有转移方程: d[i][j][k]= 石头与布相遇的概率 ×d[i+1][j][k]+ 石头与剪刀相遇的概率 ×d[i][j+1][k]+ 石头与布相遇的概率 ×d[i][j][k+1] 。事实上只剩下两种生物的状态还要向只剩下一种生物的状态转移,转移的概率都为 1 。但是为了降低编程复杂度,我们可以直接把还剩下两种生物的状态当成只剩下一种生物的状态。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 105;
int r, s, p, m;
double sum, a, b, c, d[maxn][maxn][maxn];

int main() {
    scanf("%d%d%d", &r, &s, &p);
    memset(d, 0, sizeof(d));
    d[r][s][p] = 1;
    for(int i = r; i > 0; i--) {
        for(int j = s; j > 0; j--) {
            for(int k = p; k > 0; k--) {
                // 总情况的数量
                sum = i * j + j * k  + k * i;
                // 石头和剪刀相遇
                d[i][j-1][k] += i * j / sum * d[i][j][k];
                // 剪刀和布相遇
                d[i][j][k-1] += j * k / sum * d[i][j][k];
                // 布和石头相遇
                d[i-1][j][k] += i * k / sum * d[i][j][k]; 
            }
        }
    }
    a = b = c = 0;
    m = max(max(r, s), p);
    for(int i = 1; i <= m; i++) {
        for(int j = 1; j <= m; j++) {
            // 石头幸存的情况 
            a += d[i][j][0];
            // 剪刀幸存的情况 
            b += d[0][i][j];
            // 布幸存的情况 
            c += d[i][0][j];
        }
    }
    printf("%.10f %.10f %.10f\n", a, b, c);
    return 0;
}

你可能感兴趣的:(codeforces,round-#301)