Codeforces Round 1032 (Div. 3)

A. Letter Home

要么先走到左侧,要么走到右侧,然后整行走了。

 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
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 1e5 + 7, mod = 1e9 + 7;

void solve() {
    int n, m;
    cin >> n >> m;
    vector<int> x(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> x[i];
    }
    int ans = min(abs(m - x[1]), abs(x[n] - m)) + x[n] - x[1];
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

B. Above the Clouds

考虑 b 只有一个字符,如果这个字符出现次数大于 2,那么一定 Yes。

 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
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 1e5 + 7, mod = 1e9 + 7;

void solve() {
    int n;
    string s;
    cin >> n >> s;
    vector<int> cnt(26, 0);
    for (char c : s) {
        cnt[c - 'a']++;
    }
    for (int i = 1; i < n - 1; i++) {
        if (cnt[s[i] - 'a'] > 1) {
            cout << "YES" << endl;
            return;
        }
    }
    cout << "NO" << endl;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

C. Those Who Are With Us

可以发现答案只可能是 mx,或 mx - 1。

统计每行每列中的 mx 个数,遍历每个元素,看行列上有多少个 mx,如果这个元素本身是 mx, 那么会多算一个,要减去。

 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
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 1e5 + 7, mod = 1e9 + 7;

void solve() {
    int n, m;
    cin >> n >> m;
    int mx = 0;
    map<int, int> cnt;
    map<int, int> row, col;
    vector<vector<int>> a(n + 1, vector<int>(m + 1));
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            int x;
            cin >> x;
            mx = max(mx, x);
            cnt[x]++;
            a[i][j] = x;
        }
    }
    int ans = mx;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if(a[i][j] == mx) row[i]++, col[j]++;
        }
    }

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            int tmp = row[i] + col[j];
            if (a[i][j] == mx) tmp--;
            if (tmp == cnt[mx]) {
                cout << ans - 1 << endl;
                return;
            }
        }
    }
   
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

D. 1709

可以观察到,数组极小,仅 40,暴力来搞即可,对两个数组冒泡,再从头到尾判断上面不能比下面大即可。

 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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 1e5 + 7, mod = 1e9 + 7;

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1), b(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++) {
        cin >> b[i];
    }
    vector<pair<int, int>> ans;
    for (int i = 1; i <= n; i++) {
        for (int j = 2; j <= n; j++) {
            if (a[j - 1] > a[j]) {
                swap(a[j - 1], a[j]);
                ans.push_back({1, j - 1});
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 2; j <= n; j++) {
            if (b[j - 1] > b[j]) {
                swap(b[j - 1], b[j]);
                ans.push_back({2, j - 1});
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        if (a[i] > b[i]) {
            ans.push_back({3, i});
        }
    }
    cout << ans.size() << endl;
    for (auto &p : ans) {
        cout << p.first << " " << p.second << endl;
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

E. Sponsor of Your Problems

数位 DP,从左往右看两个数。

有两种特殊情况:

  • 左侧片段和 l 相同,当前这一位只能 >= $l_i$
  • 左侧片段和 r 相同,当前这一位只能 <= $r_i$

其余情况能任意取,保证最小即可。

具体可参考代码

 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
41
42
43
44
45
46
47
48
49
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 1e5 + 7, mod = 1e9 + 7;

void solve() {
    string l, r;
    cin >> l >> r;
    int n = l.size();
    vector<vector<int>> f(2, vector<int>(2, 0)), nf(2, vector<int>(2, 0));  //优化空间,只开两层。  
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) f[i][j] = nf[i][j] = 1e9;
    }
    f[1][1] = 0;
    for (int i = 0; i < n; i++) {
        for (int a = 0; a < 2; ++a)
            for (int b = 0; b < 2; ++b) nf[a][b] = 1e9;
        int dl = l[i] - '0', dr = r[i] - '0';
        for (int a = 0; a < 2; ++a) {
            for (int b = 0; b < 2; ++b) {
                if (f[a][b] < 1e9) {
                    int lo = a ? dl : 0; //如果前面和 l 相同,则只能取大于等于 l 当前位
                    int hi = b ? dr : 9; //如果前面和 r 相同,则只能取小于等于 r 当前位
                    for (int d = lo; d <= hi; d++) {
                        int c = (d == dl) + (d == dr);  //当前代价
                        int na = a && (d == dl);  //前面相同,同时这一位也相同,保留状态
                        int nb = b && (d == dr);
                        nf[na][nb] = min(nf[na][nb], f[a][b] + c); //取最优
                    }
                }
            }
        }
        f = nf;
    }
    int ans = min({f[0][0], f[0][1], f[1][0], f[1][1]});
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

F. Yamakasi

统计前缀和出现次数,查找当前前缀和 - s 的出现次数,以大于 x 的为分界线,遇到就重置当前统计量。

以函数实现,查找 x 和 x - 1 相减即只剩下 x 的

 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
41
42
43
44
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 1e5 + 7, mod = 1e9 + 7;

void solve() {
    ll n, s, x;
    cin >> n >> s >> x;
    vector<ll> a(n + 10), pre(n + 10);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        pre[i] = pre[i - 1] + a[i];
    }
    ll ans = 0;
    auto calc = [&](ll x) {
        map<ll, int> cnt;
        cnt[0] = 1;
        ll res = 0;
        for (int i = 1; i <= n; i++) {
            if (a[i] > x) {
                cnt.clear();
            }
            if (cnt.count(pre[i] - s)) {
                res += cnt[pre[i] - s];
            }
            cnt[pre[i]]++;
        }
        return res;
    };
    ans = calc(x) - calc(x - 1);
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

G. Gangsta

设 1 出现次数为 a,0 出现次数为 b,那么 $\max(a, b) = \frac{a + b + |a - b|}{2}$

即 $f(s_{l..r}) = \frac{(c_0(l, r) + c_1(l, r)) + |c_1(l, r) - c_0(l, r)|}{2}$

现在,总和 $S$ 可以被分解为两部分: $S = \sum_{1 \le l \le r \le n} \frac{(c_0(l, r) + c_1(l, r)) + |c_1(l, r) - c_0(l, r)|}{2}$ $S = \frac{1}{2} \left( \sum_{1 \le l \le r \le n} (c_0(l, r) + c_1(l, r)) + \sum_{1 \le l \le r \le n} |c_1(l, r) - c_0(l, r)| \right)$

 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
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 1e5 + 7, mod = 1e9 + 7;

void solve() {
    int n;
    string s;
    cin >> n >> s;
    vector<ll> p(n + 1, 0);
    for (int i = 1; i <= n; i++) {
        if (s[i - 1] == '1') p[i] = p[i - 1] + 1;
        else p[i] = p[i - 1] - 1;
    }
    sort(p.begin(), p.end());
    ll ans = 0;
    ll sum = 0, tot = 0;
    for (int i = 0; i <= n; i++) {
        tot += i * p[i] - sum;
        sum += p[i];
    }
    ll total = 1ll * n * (n + 1) * (n + 2) / 6;
    ans = (total + tot) / 2; 
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

H. Ice Baby

考虑维护 dp, $dp_i$ 表示长度为 i 时,末尾的数的最小值。

dp 数组一定是不递减的,在线考虑 $l_i, r_i$ 加入时对 dp 的影响。

$$ dp'_j = \begin{cases} dp_j & \text{if } R_i < dp_{j-1} \\ & \text{(无法用 } i \text{ 延续长度为 } j-1 \text{ 的最优序列)} \\ \\ \min(dp_j, \max(L_i, dp_{j-1})) & \text{if } L_i < dp_j \text{ and } R_i \ge dp_{j-1} \\ & \text{(用 } i \text{ 延续序列是可能的,且可能优化 } dp_j \text{)} \\ \\ dp_j & \text{if } L_i \ge dp_j \\ & \text{(用 } i \text{ 延续序列无法得到比 } dp_j \text{ 更优的结果)} \end{cases} $$
 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
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 1e5 + 7, mod = 1e9 + 7;

void solve() {
    int n;
    cin >> n;
    multiset<int> s;
    // s.insert(0);
    for (int i = 1; i <= n; i++) {
        int l, r;
        cin >> l >> r;
        auto pos = s.upper_bound(r);
        s.insert(l);
        if (pos != s.end()) s.erase(pos);
        cout << s.size() << " ";
    }
    cout << endl;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}
Licensed under CC BY-NC-SA 4.0
最后更新于 Sep 11, 2025 16:27 +0800
发表了95篇文章 · 总计15万2千字
永远相信美好的事情即将发生。
使用 Hugo 构建
主题 StackJimmy 设计