Codeforces2055 996div2


赛后vp,碰到\(C\)想半天没想出来,直接昏了(x

A. Two Frogs

博弈,Alice和Bob在长为\(n\)的地方玩,每回合可以向左/向右跳,不能跳出范围或者跳到有人的地方,且不能不动,Alice先手,谁不能跳了谁就输了。

很显然和两人间距离奇偶性有关:当两人一开始距离偶数时,Alice向Bob方向走,那无论Bob怎么走接下来还是回到距离为偶数,Alice总可以继续走。所以这样Alice必胜;同理距离奇数先手必败。

Code:

void solve() {
    int n;
    cin >> n;
    int a, b;
    cin >> a >> b;
    if ((a - b) % 2 == 0) {
        cout << "YES" << '\n';
    } else {
        cout << "NO" << '\n';
    }
}

B. Crafting

有\(n\)种材料,每种材料有\(a_i\)个。

有种操作可以将某一种材料数量\(+1\),但其他材料数量\(-1\)。

现在问是否可以通过任意次操作使得每种材料不少于\(b_i\)个。

很显然,我们先让\(a + 1\)然后让\(b + 1\),得到的结果是一定劣于啥也不干的。也就是说我们最多将一种材料数量增加,且最多增加的数量就是其他材料多的数量的最小值。

Code:

void solve() {
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for (auto &i : a) cin >> i;
    for (auto &i : b) cin >> i;
    int needtoadd = -1, maxtocut = INF;
    for (int i = 0; i < n; i++) {
        if (a[i] < b[i]) {
            if (needtoadd == -1) {
                needtoadd = b[i] - a[i];
            } else {
                cout << "NO" << '\n';
                return;
            }
        } else {
            maxtocut = min(maxtocut, a[i] - b[i]);
        }
    }
    if (needtoadd > maxtocut) {
        cout << "NO" << '\n';
    } else {
        cout << "YES" << '\n';
    }
}

C. The Trail

有\(n \times m\)的一个图,有一条给定的从左上角到右下角的路径的权值未指定,其他每个点都有一个权值。

现在要求给路径填数,使得每行每列的和都为同一个数。

不妨设这个数为\(x\),那整个图的和可以表示为\(x \times n\)或者\(x \times m\),那么\(x \times n = x \times m\),也就是\(x\)应该等于\(0\)(\(n \neq m\))。

那我们就钦定每行每列都是\(0\)。

发现当走一步后,一定有一行/一列是只剩一个未知量的,根据行/列和为\(0\)求出来即可。

对于最后一个未知量,则根据行或者列来确定,可以证明这样之后行和列一定满足条件:

不妨保证列的和为\(0\),那么总和为\(0\),其他行的和也为\(0\),那么最后一行为\(0\)。

Code:

void solve() {
    int n, m;
    cin >> n >> m;
    string s;
    cin >> s;
    vector<vector<LL>> gra(n, vector<LL>(m));
    for (auto &i : gra) {
        for (auto &j : i) cin >> j;
    }
    int nowx = 0, nowy = 0;
    s += 'D';
    for (auto i : s) {
        if (i == 'D') {
            LL sum = 0;
            for (int i = 0; i < m; i++) {
                sum -= gra[nowx][i];
            }
            gra[nowx][nowy] = sum;
            nowx++;
        } else {
            LL sum = 0;
            for (int i = 0; i < n; i++) {
                sum -= gra[i][nowy];
            }
            gra[nowx][nowy] = sum;
            nowy++;
        }
    }
    for (auto i : gra) {
        for (auto j : i) {
            cout << j << ' ';
        }
        cout << '\n';
    }
}

D. Scarecrow

题意有点长不想翻译了,直接写题解罢(

可以贪心的想:

从前到后一个个考虑稻草人,维护一个值\(now\)表示现在时刻。

第一个稻草人一定得先到\(0\)然后乌鸦到\(k\)。

然后考虑其他稻草人,当这个稻草人在乌鸦当前地点的右面时,一定会向左移动来接乌鸦,这个花费的时间易得,用这个更新\(now\)和乌鸦地点。

要不然就是稻草人在乌鸦当前地点的左面,那么就向右移动最多到乌鸦所在地,根据这个更新乌鸦地点。

最后是没有稻草人了,就根据剩下距离更新\(now\)即可。

遍历稻草人的时候时刻注意乌鸦位置,到终点记得break。

Code:

void solve() {
    int n, k, p;
    cin >> n >> k >> p;
    p *= 2;
    k *= 2;
    int now = 0;
    int pp = 0;
    vector<int> arr(n);
    for (auto &i : arr) cin >> i;
    for (int i = 0; i < n; i++) {
        auto x = arr[i];
        x *= 2;
        if (i == 0) {
            now = x;
            pp = k;
        } else {
            if (x > pp) {
                if (x - now > pp) {
                    int add = (x - now - pp) / 2;
                    now += add;
                    pp += add;
                }
                pp += k;
            } else {
                int maxx = min(pp, x + now);
                pp = max(maxx + k, pp);
            }
        }
        if (pp >= p)
            break;
        if (i == n - 1) {
            now += p - pp;
        }
    }
    cout << now << '\n';
}
,

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注