Codeforces Good Bye 2021

Good Bye 2021

A. Interger Diversity

题意

给定 \(n\) 个整数,你可以选择其中的任意项,使其变成它的相反数(如把 \(x\) 变成 \(-x\)) ,问操作后的序列中最多有多少个不同的数字。

分析

记录每个数字是否出现过,如果出现过而相反数没有出现过就把它变成相反数。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
using namespace std;

void solve()
{
    int n, res = 0; cin >> n;
    map<int, bool> ex;
    for (int i = 1; i <= n; i ++ )
    {
        int x; cin >> x;
        if (ex[x] && ex[-x]) continue;
        res ++ ;
        if (!ex[x]) ex[x] = true; else ex[-x] = true;
    }
    cout << res << endl;
}

signed main()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--;) solve();
    return 0;
}

B. Mirror in the String

题意

给定长度为 \(n\) 的字符串 \(s_1s_2 \ldots s_n\) ,选择一个数字 \(k(1 \le k \le n)\) ,使其变成 \(s_1s_2 \ldots s_ks_ks_{k-1} \ldots s_1\) 。问操作后能得到的字符串的最小字典序为多少。

分析

  1. \(n = 1 \ or \ s_1 = s_2\)

    选择 \(k=1\) 即可得到字典序最小,因为选择 \(k(k \ge 2)\) 时,前两个字符依然是 \(s_1s_2\) ,后面又多了字符导致字典序不是最小。

  2. \(s1 \ != \ s2\)

    对于字符 \(s_i\) ,如果 \(s_{i+1} \gt s_i\) ,那么选择 \(k=i\) ,因为如果选择 \(k \gt i\) ,那么得到的字符串第 \(i+1\) 位一定变大了,就不是字典序最小。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
using namespace std;

void solve()
{
    int n; cin >> n;
    string s; cin >> s;
    if (n == 1 || s[0] == s[1]) return cout << s[0] << s[0] << endl, void();
    int p = 0;
    while(p < n - 1 && s[p + 1] <= s[p]) p ++ ;
    for (int i = 0; i <= p; i ++ ) cout << s[i];
    for (int i = p; i >= 0; i -- ) cout << s[i];
    cout << endl;
}

signed main()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--;) solve();
    return 0;
}

C. Representative Edges

题意

给定长度为 \(n\) 的序列 \(a\) ,每次操作可以修改其中某一个元素的值,问最小操作多少次,使得对于任意 \(1 \le l \le r \le n\) ,满足 \(a_l + a_{l+1} + \ldots + a_r = \dfrac 1 2(a_l + a_r) \times (r - l + 1)\) 。

分析

可以发现题目要求的性质为等差数列的性质,题目变为:求最少修改多少次使得序列变为等差数列。

由于数据很小 \(1 \le n \le 70\) 。我们可以固定数列任意两项作为要求的等差数列的一部分,求出其他满足该等差数列性质的个数。

假设固定 \(i, j\) ,那么对于任意一项 \(k\) ,满足等差数列性质需要: $\dfrac {a_j - a_i} {j-i} = \dfrac {a_k - a_i} {k - i} $ ,即 \((a_j - a_i) \times (k - i) = (a_k - a_i) \times (j - i)\) 。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define rep(i, x, y) for (int i = x; i <= y; i ++ )
using namespace std;
const int N = 1000, M = 400010, mod = 998244353, INF = 0x3f3f3f3f;

int a[N];

void solve()
{
    int n, ret; cin >> n; ret = max(0, n - 2);
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    rep(i, 1, n) rep(j, i + 1, n)
    {
        int save = 0;
        rep(k, 1, n) if ((a[k] - a[i]) * (j - i) == (a[j] - a[i]) * (k - i)) ++ save;
        ret = min(ret, n - save);
    }
    cout << ret << endl;
}

signed main()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--;) solve();
    return 0;
}

D. Keep the Average High

题意

给定长度为 \(n\) 的序列 \(a\) ,选出最多的元素,满足对于任意 \(1\le l \lt r \le n\) (\(l, r\) 均指原序列的下标),满足以下至少一项:

  1. 存在至少一项 \(l \le k \le r\) 没有被选择。
  2. \(a_l + a_{l+1} \ldots a_r \ge x \times (r - l + 1)\) 。

问能够选择最多多少个元素。

分析

对于任意 \(l, r\) ,如果其中有一个没有被选择,那么一定满足限制,所以只需要考虑 \([l, r]\) 都被选择时是否满足限制。

注意第 \(2\) 个限制,等价于 \((a_l - x) + (a_{l + 1} - x) + \ldots + (a+r - x) \ge 0\) 。

注意到 \([l, r]\) 是连续的,我们设 \(p(i) = \sum_{i=1}^i a_i - x\) ,那么上述限制等价于 \(p(r) - p(l-1) \ge 0\) 。

假设目前枚举到第 \(i\) 位,那么我们需要考虑后两位,如果 \(p(i + 2) - p(i) \lt 0\) ,即 \(a(i+1) + a(i+2) \lt 0\) ,那么我们不能全部取到,否则令 \(l = i+1, r=i+2\) ,不满足限制。如果满足 \(p(i+2) - p(i) \ge 0\) ,因为前面满足的序列加上第 \(i+1\) 位不一定不小于 \(0\) ,那么我们取最大值,把 \(i+1\) 位放到待判断的序列中,即:
\(a_1 \ldots a_qq_{q+1} \ldots a_i \ldots a_n\) ,区间 \([q, i]\) 为满足限制的区间,而 \(i+1\) 进入到待选择区域。这样我们就不仅只考虑满足限制的最后一个位置后面的两个位置了。对于带选择区间 \([l, r]\) ,因为加上了 \(a_r\) 导致 \(p(r) - p(l-1) < 0\) ,那么只需要不选择 \(r\) 即可,因为 \([l, r-1]\) 加上前面满足的区间依然不小于零。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N = 200010;

int a[N], pre[N];

void solve()
{
    int n, x, ret, mx = 0; cin >> n; ret = n;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    cin >> x;
    for (int i = 1; i <= n; i ++ ) pre[i] = pre[i-1] + a[i] - x;
    for (int i = 2; i <= n; i ++ )
        if (pre[i] < mx) { -- ret; mx = pre[i]; ++ i; }
        else mx = max(mx, pre[i-1]);
    cout << ret << endl;
}

signed main()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--;) solve();
    return 0;
}
上一篇:Good Bye 2021: 2022 is NEAR


下一篇:gvim在linux下菜单无法显示问题