Codeforces Round 1032(Div. 3)[A-F]

A. Letter Home

题意

给你 \(n\) 个不同的整数放在数组 \(x\) 中,给一个整数s。

你的位置在 \(s\),你可以进行任意次操作一或者二

  • 操作一:位置 \(+1\)
  • 操作二:位置 \(-1\)

问你经过所有 \(x_i\) 的最小步数

tag: 电梯算法scan

思路

使用电梯调度的算法思想,从 \(s\) 出发计算\(max(先上到最顶部再下到最底部的操作数,先下到最底部再上到最顶部的操作数)\)

Code (C++)
void whx()
{
    cin >> n >> s;
    int ma = -1, mi = 1e18;
    for (int i = 1; i <= n; i ++ ) cin >> x[i], ma = max(ma, x[i]), mi = min(mi, x[i]);
    int ans = 0;
    if (s >= mi && s <= ma)
    {
        ans = min(ma - s + ma - mi, s - mi + ma - mi);
    }
    else
    {
        // debug(s, ma, mi);
        if (s >= ma) ans = s - mi;
        else ans = ma - s;
    }
    cout << ans << "\n";
}

B. Above the Clouds

题意

给你一个长度为 \(n\) 的字符串 \(s\),仅由小写字母构成。 请判断是否存在三个非空字符串 \(a\)\(b\)\(c\) 满足以下条件:

  • \(a + b + c = s\)
  • \(b\) 是 字符串 \(a + c\) 的子串

tag: 思维

思路

贪心一下,b只选1个字符符合条件的概率最大,如果一个字符都不符合条件,那么选多了更不行。用map记录下来每个字符的个数,然后遍历b可能的字符,如果map存在除b之外的和b相同的字符,那么就存在符合条件的\(a\)\(b\)\(c\)

Code (C++)
void whx()
{
    int n;
    string s;
    cin >> n >> s;
    unordered_map mp;
    for (int i = 0; i < n; i ++ )
    {
        mp[s[i]] ++;
    }
    for (int i = 1; i < n - 1; i ++ )
    {
        if (mp[s[i]] >= 2)
        {
            cout << "Yes\n";
            return;
        }
    }
    cout << "No\n";
}

C. Those Who Are With Us

题意

给你一个 \(n\)\(m\) 列的矩阵 \(a\),进行一次操作:

  • 选择两个数字 \(1 \leq x \leq n\)\(1 \leq y \leq m\)
  • 对于所有的单元格 \((i, j)\) 中的 \(i = x\)\(j = c\) ,将 \(a_{ij}\)\(1\)

求矩阵a进行一次操作后的最小最大值。

tag: 思维

思路

首先的输入时预先存下最大值 \(ma\)

不难想到,答案只可能是 \(ma\)\(ma - 1\)

当我们进行一次操作覆盖了所有的 \(ma\) 后 答案就是 \(ma - 1\),反之 \(ma\)

如何求一次操作覆盖的 \(ma\) 个数,提前存起来每行每列 \(ma\) 的个数然后枚举一遍就好了。

Code (C++)

void whx()
{
    int n, m;
    cin >> n >> m;
    vector> g(n + 1, vector(m + 1));
    int ma = -1;
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            cin >> g[i][j], ma = max(ma, g[i][j]);
    vector x(n + 1), y(m + 1);// 记录每一列最大值的个数
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= m; j ++ )
        {
            if (g[i][j] == ma)
            {
                cnt ++;
                x[i] ++;
                y[j] ++;
            }
        }
    }
    // 遍历每个十字,如果最大值的个数等于cnt,那么最大值-1,否则不变
    int ans = ma;
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= m; j ++ )
        {
            if (x[i] + y[j] - (g[i][j] == ma) == cnt)
            {
                ans = ma - 1;
            }
        }
    }
    cout << ans << "\n";
}

D. 1709

题意

给你长度为 \(n\) ($ n \leq 40 $)的 \(a\) 数组和 \(b\) 数组,保证从 \(1\)\(2*n\) 的每个整数要么出现在数组 \(a\) 中,要么出现在数组 \(b\) 中。

你最多可以执行 \(1709\) 次以下操作之一:

  • 选择索引 \(1 \leq i < n\)\(swap(a_i, a_{i+1})\)
  • 选择索引 \(1 \leq i < n\)\(swap(b_i, b_{i+1})\)
  • 选择索引 \(1 \leq i \leq n\)\(swap(a_i,b_i)\)

能否找出 \(a\) 数组和 \(b\) 数组 满足以下两个条件:

  • 对于每个 \(1 \leq i < n\)\(ai \leq a_{i + 1}\)\(b_i<b_{i+1}\) 都成立
  • 对于每一个 \(1 \leq i \leq n\)\(a_i < b_i\) 成立。

tag: 冒泡排序

思路

同时遍历 \(a\)\(b\) 数组,对他进行冒泡排序,记录交换个数。此时满足条件一。

然后检查条件二,遍历一遍,如果 \(a_i < b_i\) 满足,反之交换。

对于 \(a_i > b_i\) ,一定有 \(a_{i + 1} > a_i\) , 所以也有 \(a_{i + 1} > b_i\) ,交换\(a_i,b_i\) 后仍然满足条件一。

复杂度分析: 排序O(\(n^2\)) + 遍历交换 \(a\)\(b\) O(\(n\)) \(=>\) \(1640 < 1709\)

Code (C++)

void whx()
{
    int n;
    cin >> n;
    vector 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 ans;
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= n - i; j ++ )
        {
            if (a[j] > a[j + 1])
            {
                swap(a[j], a[j + 1]);
                ans.push_back({1, j});
            }
            if (b[j] > b[j + 1])
            {
                swap(b[j], b[j + 1]);
                ans.push_back({2, j});
            }
        }
    }
    for (int i = 1; i <= n; i ++ )
    {
        if (a[i] > b[i])
        {
            swap(a[i], b[i]);
            ans.push_back({3, i});
        }
    }
    cout << ans.size() << "\n";
    for (auto& [op, v] : ans) cout << op << " " << v << "\n";
}

E. Sponsor of Your Problems

题意

定义 \(f(a, b)\) 为数字 \(a\)\(b\) 的十进制表示 位数相同的位置数。

例如: \(f(12, 21) = 0\), \(f(31, 37) = 1\), \(f(19891, 18981) = 2\), \(f(54321, 24361) = 3\)

给你两个长度相同的十进制整数 \(l\)\(r\),考虑所有的 \(l \leq x \leq r\)。找出 \(f(l, x)+ f(x, r)\) 的最小值

tag: 拆位,模拟,分类讨论

思路

情况 \(1\):如果 \(l_i 和 r_i\) 相差大于 \(2\) 直接选择 中间的 那么 就是 \(0\) 个 贡献。

情况 \(2\):如果 $l_i 和 r_i $ 相差等于 \(0\) 那么 必然产生 \(2\) 个 贡献。

情况 \(3\):如果 \(l_i 和 r_i\) 相差等于 \(1\) 需要考虑选 \(l\) 还是 \(r\)

从高位向低位考虑。

如果出现情况 \(1\) 那么后续就可以选任意数了, 直接停止计数。

\(l\):1nnnn
\(r\):3nnnn
x的第一位选择了 \(2\),由于 \(x\) 在 l 和 r 之间,所以 \(2....\) 后面可以取任何数。

对于连续的情况 \(2\) ,持续更新贡献 \(+2\)

如果遇到了情况 \(3\) ,先更新贡献 \(+1\) ,然后考虑选择 \(l\) 还是 \(r\):

一般情况:

128nnn

130nnn

2 或者 3 之后都停了

特殊情况:

1299nn

1300nn

\(2\) 之后只能选 \(9\)

\(3\) 之后只能选 \(0\)

会产生一段连续的贡献再停止

Code (C++)

void whx()
{
    int l, r;
    cin >> l >> r;
    vector a, b;
    while (l)
    {
        a.push_back(l % 10);
        l /= 10;
    }
    while (r)
    {
        b.push_back(r % 10);
        r /= 10;
    }
    reverse(a.begin(), a.end());
    reverse(b.begin(), b.end());
    int idx = 0, ans = 0;
    while (a[idx] == b[idx] && idx <= a.size() - 1) ans += 2, idx ++;
    if (idx >= a.size())
    {
        cout << ans << "\n";
        return;
    }
    if ((a[idx] + 1) % 10 == b[idx])
    {
        ans ++, idx ++;
        while (idx <= a.size() - 1)
        {
            bool fa = (a[idx] == 9);
            bool fb = (b[idx] == 0);
            if (!fa)
            {
                cout << ans << "\n";
                return;
            }
            else if (!fb)
            {
                cout << ans << "\n";
                return;
            }
            idx ++, ans ++;
        }
        cout << ans << "\n";
    }
    else
    {
        cout << ans << "\n";
    }
}

F. Yamakasi

题意

给你一个长度为 n 的数组 a ,和两个整数 s ,x 。计算元素之和等于 s 且 最大值等于 x 的数组子段的数目。

具体就是: 输出 \(1 \leq l \leq r \leq n\) 满足如下条件的数对:

  • \(a_l + a_{l + 1} + \ldots + a_r = s\).
  • \(\max(a_l, a_{l + 1}, \ldots, a_r) = x\).

tag: 前缀和

思路

\(a\) 数组 的 前缀和数组 是 \(f\)

\(s = f[r] - f[l - 1] => f[l - 1] = f[r] - s\)

用map维护 \(r\) 之前的所有 \(f_i\) 的值, 枚举 \(r\),同时查找map中 \(f[r] - s\) 的个数,更新贡献。

同时还要满足一个条件,就是 \([l, r]\) 中 最大值要是 \(x\)

当枚举 \(r\) 的时候 如果 \(a[r] > x\) 那么这一位和前面的位置都不能作为 \(l\) 了,这时候就把 map 清空。

当枚举到一个 \(a[r] = x\) ,把 \(l\) 更新到 \(r - 1\) 位置,更新对应map \(+1\)

Code (C++)

void whx()
{
    int n, s, x;
    cin >> n >> s >> x;
    vector a(n + 1), f(n + 1);
    for (int i = 1; i <= n; i ++ )
    {
        cin >> a[i];
        f[i] = f[i - 1] + a[i];
    }
    map mp;
    int ans = 0, l = 0;
    for (int r = 1; r <= n; r ++ )
    {
        if (a[r] > x)
        {
            mp.clear();
            l = r;
        }
        else
        {
            if (a[r] == x)
            {
                while (l < r)
                {
                    mp[f[l ++]] ++;
                }
            }
            int cnt = mp[f[r] - s];
            // debug(l, r, cnt);
            ans += mp[f[r] - s];
        }
    }
    cout << ans << "\n";
}

posted @ 2025-07-03 20:42  __whx  阅读(32)  评论(0)    收藏  举报