Post

Educational Codeforces Round 151 [Rated for Div. 2]

Educational Codeforces Round 151 [Rated for Div. 2]

Educational Codeforces Round 151 [Rated for Div. 2]

A

题目大意

输入 $n,k,x$,有 $1$ 到 $k$ 中除了 $x$ 的所有数,每个数可以取任意次,任意给出一种取法,让取出来的所有的数和为 $n$。

思路

如果 $k=1$,则 $x=1$,显然不存在。
如果 $k>1$ 且 $x \neq 1$,则用 $1$ 可以得到 $n$。
那么,只需要考虑 $k>1$ 且 $x=1$ 的情况。
如果 $k=2$ ,则只能用 $2$,这时当 $n$ 被 $2$ 整除时可以得到 $n$,否则不行。
如果 $k \geq 3$,则:如果 $n$ 为偶数,用 $2$ 可以得到;如果 $n$ 为奇数,让它减 $3$ 变为偶数后也可以用 $2$ 得到;特殊判断如果 $n=1$ 则无法得到。
赛时认为 $n$ 如果可以得到,一定可以由 $n / i$ 个 $i$ 和 $1$ 个 $n \% i$ 得到,可以被数据 7 3 1 hack。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void solve() {
    int n, k, x;
    cin >> n >> k >> x;
    if (x != 1) {
        cout << "YES\n" << n << endl;
        rep(i, 1, n) cout << "1 ";
        cout << endl;
        return;
    }
    if (k == 1) {
        cout << "NO\n";
        return;
    }
    if (x == 1 && n == 1) {
        cout << "NO\n";
        return;
    }
    if (k != 2) {
        if (n % 2 == 0) {
            cout << "YES\n" << n / 2 << endl;
            rep(i, 1, n / 2) cout << "2 ";
            cout << endl;
            return;
        }
        cout << "YES\n" << 1 + (n - 3) / 2 << endl;
        rep(i, 1, (n - 3) / 2) cout << "2 ";
        cout << "3 ";
        cout << endl;
        return;
    } else {
        if (n % 2 == 1)
            cout << "NO\n";
        else {
            cout << "YES\n" << n / 2 << endl;
            rep(i, 1, n / 2) cout << "2 ";
            cout << endl;
            return;
        }
    }
}

B

题目大意

平面图上有三个点 $A,B,C$,两个人b和c起始在 $A$ 上,每次移动可以往上下左右四个方向移动一格。b和c想要在保证自己走最近的一条路回到 $B,C$ 的情况下,走共同的路多一些。问它们最多能共同走多少格路。

思路

他们都走最近的路,意味着它们只能从上/下,左/右中各选一个方向走。因为它们的起点相同,如果它们同上或同下,同左或同右,说明可以同走一段路。

代码

1
2
3
4
5
6
7
8
9
10
11
12
void solve() {
    int x[3], y[3], ans = 1;
    rep(i, 0, 2) cin >> x[i] >> y[i];
    int dx[2] = {x[0] - x[1], x[0] - x[2]}, dy[2] = {y[0] - y[1], y[0] - y[2]};
    if (dx[0] * dx[1] > 0) {
        ans += min(abs(dx[0]), abs(dx[1]));
    }
    if (dy[0] * dy[1] > 0) {
        ans += min(abs(dy[0]), abs(dy[1]));
    }
    cout << ans << endl;
}

C

题目大意

给出长度 $m$ ,字符串 $s$,两个长度为 $m$ 的由数字组成的字符串 $l,r$。问能否设计一个由数字 $0$ 到 $9$ 组成的长度为 $m$ 的密码,要求密码不能是字符串 $s$ 的子串(子串可以是不连续的),且密码的第 $i$ 位数在 $l_i$ 与 $r_i$ 之间。

思路

对于密码的第 $i$ 位,所有在 $l_i$ 与 $r_i$ 之间的数满足要求,它们构成一个集合 $S_i$。试图将字符串 $s$ 分为 $m$ 段,如果对于每个 $i$,都满足第 $i$ 段中包含 $S_i$ 中的所有元素,那么很显然找不到这样的密码。否则可以找到。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
char s[300010], l[12], r[12];
int m;
void solve() {
    int p = 0, len;
    unordered_set<int> a;
    scs(s);
    len = strlen(s);
    scd(m);
    scs(l);
    scs(r);
    rep(i, 0, m - 1) {
        rep(j, l[i] - '0', r[i] - '0') { a.insert(j); }
        for (; p < len; p++) {
            if (a.empty())
                break;
            a.erase(s[p] - '0');
        }
    }
    if (a.empty())
        cout << "NO\n";
    else
        cout << "YES\n";
}

D

题目大意

选手的初始rating是 $0$,给出它 $n$ 场比赛的rating变化值 $a_i$。
rating变化的机制:当选手的rating达到 $k$ 之后,如果之后它的某次rating变化将使它的rating低于 $k$ 了,它的rating只会变为 $k$。
问当 $k$ 取多少时,选手最后的rating会最高。

思路

显然答案应为 $\sum_{1}^{m} a_i$。假设在达到 $k$ 后,rating清零,之后的rating以 $k=0$ 计算,最后 ${rating} + k$ 即为选手最终的rating。因此,我们只需要试图处理出 $k=0$ 时每个后缀的rating,就能够解决问题。
求每个后缀的rating值,用dp来解决。对于每个后缀,我们可以把它拆分成两段,前一段的和为负数,后一段的和及其所有前缀和均为正数,该后缀的值即为后一段的和。用一个变量 $w$ 来记录前一段的和,如果 $w$ 为正数,说明它应该被划到后一段中,sufsum[i]=sufsum[i+1]+w,w=0 ,如果 $w$ 为负数,那么将它继续累积起来,sufsum[i]=sufsum[i+1]

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
long long a[300010], sufsum[300010], ans, k, maxx = -INF;
int n;
void solve() {
    k = 0;
    maxx = -INF;
    posi = nega = 0;
    cin >> n;
    rep(i, 1, n) {
        sufsum[i] = 0;
        cin >> a[i];
    }
    sufsum[n + 1] = 0;
    int w = 0;
    per(i, n, 1) {
        w += a[i];
        if (w > 0) {
            sufsum[i] = w + sufsum[i + 1];
            w = 0;
        } else {
            sufsum[i] = sufsum[i + 1];
        }
    }
    rep(i, 0, n - 1) {
        k += a[i];
        if (k + sufsum[i + 1] > maxx) {
            maxx = k + sufsum[i + 1];
            ans = k;
        }
    }
    cout << ans << endl;
}
This post is licensed under CC BY 4.0 by the author.