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

来源:互联网 发布:golang mongodb 查询 编辑:程序博客网 时间:2024/05/20 21:20

题目链接


A. Launch of Collider(Codefoeces 699A)

思路

因为所有粒子的速度都是相同的,所以两个粒子发生碰撞的条件是,两个粒子相邻且右方的粒子向左运动,左方的粒子向右运动。

代码

#include <bits/stdc++.h>using namespace std;const int maxn = 2e5 + 10;char s[maxn];int n, ans, a[maxn];int main() {    scanf("%d%s", &n, s);    for(int i = 0; i < n; i++) {        scanf("%d", &a[i]);    }    ans = INT_MAX;    for(int i = 1; i < n; i++) {        if(s[i] == 'L' && s[i-1] == 'R') {            ans = min(ans, (a[i] - a[i-1]) / 2);        }    }    if(ans == INT_MAX) {        puts("-1");    }    else {        printf("%d\n", ans);    }    return 0;}

B. One Bomb(Codeforces 699B)

思路

因为直接算出放炸弹的位置不是很方便,所以想到枚举放炸弹的位置,然后用常数的复杂度(根据数据规模)判断将炸弹放在这个位置是否能将所有的墙炸毁。既然判断的复杂度被限制在常数,那么我们事先需要知道一些信息。为此我们用 r[i] 表示第 i 行的墙的数量,用 c[i] 表示第 i 列的墙的数量。当我们枚举炸弹的位置枚举到 ij 列的时候,只要看 tmp=r[i]+c[j] 是否等于墙的总数就可以知道是否能够一次性炸完所有的墙。注意,当 ij 列上有墙的时候我们要将 tmp 再减去 1 ,以免重复统计。

代码

#include <bits/stdc++.h>using namespace std;const int maxn = 1010;bool ok;char G[maxn][maxn];int n, m, x, y, cnt, tmp, r[maxn], c[maxn];int main() {    scanf("%d%d", &n, &m);    for(int i = 0; i < n; i++) {        scanf("%s", G[i]);        for(int j = 0; j < m; j++) {            if(G[i][j] == '*') {                r[i]++;                c[j]++;                cnt++;            }        }    }    for(int i = 0; i < n; i++) {        for(int j = 0; j < m; j++) {            tmp = r[i] + c[j] - (G[i][j] == '*');            if(tmp == cnt) {                ok = true;                x = i + 1;                y = j + 1;            }        }    }    if(ok == false) {        puts("NO");    }    else {        printf("YES\n%d %d\n", x, y);    }    return 0;}

C. Vacations(Codeforces 699C)

思路

我们可以将这个问题转化为求主人公最多可以工作多少天(这样比较自然),如果用 m 来表示这个量,那么答案就是 nm 。如果我们能知道前i天(包括第 i 天)的在某个状态 s (表示主人公的选择)下主人公工作最大天数,那么根据状态 s 下第 i+1 天主人公的选择,我们就可以更新前 i+1 天主人公工作最大天数。因此我们定义状态 (i,j) ,表示前 i 天的所有情况都已经考虑,在第 i 天选择了 j (0:休息,1:比赛,2:运动)的状态,那么 d[i][j] 就是该状态下的主人公工作的最大天数。我们可以根据规则(相邻两天不能干相同的事儿,当天没有比赛就没法比赛,当天体育馆不开就没法运动)来用 d[i][0],d[i][1],d[i][2] 来更新 d[i+1][0],d[i+1][1],d[i+1][2] 。最后的答案是 d[n][0],d[n][1],d[n][2] 中的最大值。

代码

#include <bits/stdc++.h>using namespace std;const int maxn = 110;int n, m, a[maxn], d[maxn][3];int main() {    scanf("%d", &n);    for(int i = 1; i <= n; i++) {        scanf("%d", &a[i]);    }    // 枚举今天是哪天    for(int i = 0; i < n; i++) {    // 枚举今天做什么        for(int j = 0; j < 3; j++) {            // 枚举明天做什么            for(int k = 0; k < 3; k++) {                // 不符合规则的话枚举下一件事儿                if(j && (j == k || !(a[i+1] & j))) {                    continue;                }                // 用今天的最优值更新明天的最优值                d[i+1][j] = max(d[i+1][j], d[i][k] + (j > 0));            }            m = max(m, d[i+1][j]);        }    }    printf("%d\n", n - m);    return 0;}

D. Fix a Tree(Codeforces 699D)

思路

题给的图是 n 个点和 n 条边的图,在纸上把样例画一画就能看出这个图的每个连通分量都含有一个圈(可能是自环,重边或其它圈)。这样,所以既让图连通,又消去除了一个自环以外的其它圈的办法就是:指定一个自环作为根节点(如果没有自环就让某个圈上的某个点的某条边指向该点),将所有其它圈上的某条边的某端拆开,连接到这个根节点上。显然,假如连通分量的个数为 c 的话,修改 c1 条边就能使图变成树了。怎么实现呢?首先我们尝试指定一个修改图之前就带自环的点为根节点。然后对于每个没访问过的点 u ,沿边访问该点所在连通分量中的所有点,同时为访问过的点加上访问标记。一旦访问到了标记过的点 v ,就表示可能出现以下两种情况中的一种情况: v 是之前标记的点, v 是圈上的点。前者可以不用理会,后者又可以根据情况不同有两种处理方式:若之前成功指定到了根节点,那么这个点的某条边就要连接到根节点上,若之前没能指定根节点,那么这个点的某条边就要连接到自己,然后该点就被指定为根节点。最后在将u枚举完后输出重新连接的边就好了。

代码

#include <bits/stdc++.h>using namespace std;const int maxn = 2e5 + 10;int n, root, cur, ans, a[maxn], c[maxn];int main() {    scanf("%d", &n);    for(int i = 1; i <= n; i++) {        scanf("%d", &a[i]);    }    // 尝试指定根节点    for(int i = 1; i <= n; i++) {        if(a[i] == i) {            root = i;        }    }    // 访问没访问过的点    for(int i = 1; i <= n; i++) {        if(c[i] != 0) {            continue;        }        // 从i出发,访问i所在的连通分量        for(cur = i; c[cur] == 0; cur = a[cur]) {            // 加上访问标记            c[cur] = i;        }        // 若访问过的点是之前访问过的或该点就是根节点        if(c[cur] != i || root == cur) {            continue;        }        // 若之前没能指定根节点就指定cur为根节点        root = root ? root : cur;        // 将边重新连接        a[cur] = root;        ans++;    }    printf("%d\n", ans);    for(int i = 1; i <= n; i++) {        printf("%d ", a[i]);    }    return 0;}

(其它题目略)

0 0