Codeforces Round 834

比赛链接

A

题目

知识点:模拟。

确定开头字母,然后循环比较即可。

时间复杂度 (O(n))

空间复杂度 (O(n))

题解

#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool solve() {
    string s;
    cin >> s;
    string t = "Yes";
    int pos = -1;
    if (s[0] == t[0]) pos = 0;
    else if (s[0] == t[1]) pos = 1;
    else if (s[0] == t[2]) pos = 2;
    else return false;
    for (auto ch : s) {
        if (ch != t[pos]) return false;
        pos = (pos + 1) % 3;
    }
    cout << "YES" << 'n';
    return true;
}
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << "NO" << 'n';
    }
    return 0;
}

B

题目

知识点:枚举。

找到总和等于 (sum + s) 的排列,其中 (sum) 是原来序列的和。这个排列的最大数字不能小于原来序列里的最大数字,否则不合法。

时间复杂度 (O(n))

空间复杂度 (O(1))

题解

#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool solve() {
    int m, s;
    cin >> m >> s;
    int mx = 0, sum = 0;
    for (int i = 1;i <= m;i++) {
        int x;
        cin >> x;
        sum += x;
        mx = max(x, mx);
    }
    int ans = -1;
    for (int i = 1;i <= 70;i++) {
        if (i * (i + 1) / 2 == sum + s) {
            ans = i;
            break;
        }
    }
    if (ans >= mx) cout << "YES" << 'n';
    else cout << "NO" << 'n';
    return true;
}
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << 'n';
    }
    return 0;
}

C

题目

知识点:贪心。

分类讨论:

  1. (a=b) ,不用操作。
  2. (|a-b|geq x) ,一次操作。
  3. 先将 (a)(l) (或 (r) ),再将 (l) (或 (r) )变成 (x) ,两次操作(如果可以的话)。
  4. 先将 (a)(l) (或 (r) ),再将 (l) (或 (r) )变成 (r) (或 (l) ),再将 (r) (或 (l) )变成 (x) ,三次操作(如果可以的话)。
  5. 无解,因为 (a) 变换到 (l)(r) 将会拥有与 (b) 的最大距离,再不行就无解。

时间复杂度 (O(1))

空间复杂度 (O(1))

题解

#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool solve() {
    int l, r, x;
    int a, b;
    cin >> l >> r >> x;
    cin >> a >> b;
    if (a == b) cout << 0 << 'n';
    else if (abs(a - b) >= x) cout << 1 << 'n';
    else if (a - l >= x && b - l >= x || r - a >= x && r - b >= x) cout << 2 << 'n';
    else if (a - l >= x && r - l >= x && r - b >= x || r - a >= x && r - l >= x && b - l >= x) cout << 3 << 'n';
    else cout << -1 << 'n';
    return true;
}
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << 'n';
    }
    return 0;
}

D

题目

知识点:数论,贪心。

显然尽可能配对 (2)(5) 因子,随后尽可能乘 (10)

先找到 (n) 中已有的 (2)(5)因子数量,然后先用 (mul) 配平因子数(这样操作的得到的 (mul) 最小)。

之后,给 (mul)(10) 直到再次操作会超过 (m)

最后把 (mul) 加倍到最大值 (m) 内最大值。

时间复杂度 (O(log n + log m))

空间复杂度 (O(1))

题解

#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool solve() {
    int n, m;
    cin >> n >> m;
    int t = n;
    int c2 = 0, c5 = 0;
    while (t % 2 == 0) t /= 2, c2++;
    while (t % 5 == 0) t /= 5, c5++;
    int mul = 1;
    while (c2 < c5 && mul * 2LL <= m) mul *= 2, c2++;
    while (c2 > c5 && mul * 5LL <= m) mul *= 5, c5++;
    while (mul * 10LL <= m) mul *= 10;
    cout << 1LL * n * (m / mul) * mul << 'n';
    return true;
}
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << 'n';
    }
    return 0;
}

E

题目

显然贪心策略是从小到大吸收,考虑道具使用顺序。

方法一

知识点:枚举,dfs。

只有三个道具,直接搜索所有使用顺序即可,每次先把能吸收的吸收了。

时间复杂度 (O(n))

空间复杂度 (O(n))

方法二

知识点:线性dp。

(dp[i][j][k]) 表示吸收了前 (i) 个人, (2) 倍道具剩 (j) 个, (3) 倍道具剩 (k) 个的最大能量。

转移时,先从吸收了 (i-1) 个人的状态转移到吸收了 (i) 个人的状态,再考虑吸收了 (i) 个人的状态后使用道具的情况。

使用道具时的转移不需要考虑转移顺序。某个状态被其他的状态更新后,再使用道具的状态一定会被更新他的状态包括,因此不需要考虑更新顺序。

时间复杂度 (O(n))

空间复杂度 (O(n))

题解

方法一

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n;
int a[200007];
int dfs(int pos, int cntg, int cntb, ll h) {
    while (pos <= n && h > a[pos]) h += a[pos++] / 2;
    int mx = pos - 1;
    if (cntg >= 1) mx = max(mx, dfs(pos, cntg - 1, cntb, h * 2));
    if (cntb >= 1) mx = max(mx, dfs(pos, cntg, cntb - 1, h * 3));
    return mx;
}
bool solve() {
    int h;
    cin >> n >> h;
    for (int i = 1;i <= n;i++) cin >> a[i];
    sort(a + 1, a + n + 1);
    cout << dfs(1, 2, 1, h) << 'n';
    return true;
}
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << 'n';
    }
    return 0;
}

方法二

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[200007];
ll f[200007][3][2];
bool solve() {
    int n, h;
    cin >> n >> h;
    for (int i = 1;i <= n;i++) cin >> a[i];
    sort(a + 1, a + n + 1);
    for (int i = 1;i <= n;i++)
        for (int j = 0;j <= 2;j++)
            for (int k = 0;k <= 1;k++)
                f[i][j][k] = 0;
    f[0][2][1] = h;
    f[0][1][1] = h * 2;
    f[0][2][0] = h * 3;
    f[0][0][1] = h * 4;
    f[0][1][0] = h * 6;
    f[0][0][0] = h * 12;
    for (int i = 1;i <= n;i++) {
        for (int j = 0;j <= 2;j++)
            for (int k = 0;k <= 1;k++)
                if (f[i - 1][j][k] > a[i]) f[i][j][k] = max(f[i][j][k], f[i - 1][j][k] + a[i] / 2);
        for (int j = 0;j <= 2;j++) {
            for (int k = 0;k <= 1;k++) {
                if (j >= 1) f[i][j - 1][k] = max(f[i][j - 1][k], f[i][j][k] * 2);
                if (k >= 1) f[i][j][k - 1] = max(f[i][j][k - 1], f[i][j][k] * 3);
                if (j >= 2) f[i][j - 2][k] = max(f[i][j - 2][k], f[i][j][k] * 4);
                if (j >= 1 && k >= 1) f[i][j - 1][k - 1] = max(f[i][j - 1][k - 1], f[i][j][k] * 6);
                if (j >= 2 && k >= 1) f[i][j - 2][k - 1] = max(f[i][j - 2][k - 1], f[i][j][k] * 12);
            }
        }
    }
    for (int i = n;i >= 0;i--)
        for (int j = 0;j <= 2;j++)
            for (int k = 0;k <= 1;k++)
                if (f[i][j][k]) {
                    cout << i << 'n';
                    return true;
                }
    return true;
}
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << 'n';
    }
    return 0;
}

F

题目

知识点:贪心,枚举。

显然答案不会大于等于 (p) ,即只需要考虑 (a_n) 关于缺失数字的大小即可,用 set 存出现过的数。

如果没有小于 (a_n) 的缺失数字,就不需要进位,设最大的缺失数字为 (mx) (不存在则设为 (a_n) ),答案为 (mx – a_n)

如果有小于 (a_n) 的缺失数字,则必须进位。进位后,一定会出现 (0) 以及模拟进位后变化的最高位的数字,需要纳入 set 。随后找到小于 (a_n) 的最大缺失数字 (mx) (不存在则设为 (0) ),答案为 (mx + p-a_n)

因为给出的数字最多只有 (100) 个,所以每次找数字的次数不会超过 (100) 次。

时间复杂度 (O(n log n))

空间复杂度 (O(n))

题解

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[107];
bool solve() {
    int n, p;
    cin >> n >> p;
    for (int i = 1;i <= n;i++) cin >> a[i];
    set<int> st;
    for (int i = 1;i <= n;i++) st.insert(a[i]);
    bool cf = 0;
    for (int i = a[n];i >= 0 && !cf;i--) cf |= !st.count(i);
    if (cf) {
        st.insert(0);
        for (int i = n - 1;i >= 0;i--) {
            if (a[i] + 1 < p) {
                st.insert(a[i] + 1);
                break;
            }
        }
        int mx = a[n] - 1;
        while (mx > 0 && st.count(mx)) mx--;
        cout << mx + p - a[n] << 'n';
    }
    else {
        int mx = p - 1;
        while (mx > a[n] && st.count(mx)) mx--;
        cout << mx - a[n] << 'n';
    }
    return true;
}
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << 'n';
    }
    return 0;
}

G

题目

知识点:构造,二分,贪心。

显然,(a_{2i} = b_i) 最优,接下来考虑 (a_{2i-1})

首先,我们希望出现在前面的数字尽可能小,但因为留下的数字是较大的,不一定能让后面数字有解。于是,若要确定这个数字,那么就必须每次都需要检查一遍后面的数字是否还有解,这样很难以较小复杂度实现。

但是,我们知道出现在后面的数字要尽可能大,我们可以从后往前确定数字,这样就尽可能保留了小的数字,使得前面的数有解。并且,保留的数字不会比这种方案更小,因此如果前面的数字还是无解,那就真的无解。

因此,我们先把 (1)(n) 存在 set 中,把出现过的数字删除。如果删除的数字已经删过,那么不可能是个排列,所以无解。然后,从后往前,确定未出现的数中小于 (b_i) 的最大数当作 (a_{2i-1}) ,如果没有则无解。

时间复杂度 (O(n log n))

空间复杂度 (O(n))

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[200007], b[100007];
bool solve() {
    int n;
    cin >> n;
    for (int i = 1;i <= n / 2;i++) cin >> b[i], a[i * 2] = b[i];
    set<int> st;
    for (int i = 1;i <= n;i++) st.insert(i);
    for (int i = 1;i <= n / 2;i++) {
        if (!st.count(b[i])) return false;
        st.erase(b[i]);
    }
    for (int i = n / 2;i >= 1;i--) {
        auto pos = st.lower_bound(b[i]);
        if (pos == st.begin()) return false;
        a[i * 2 - 1] = *prev(pos);
        st.erase(prev(pos));
    }
    for (int i = 1;i <= n;i++) cout << a[i] << ' ';
    cout << 'n';
    return true;
}
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << 'n';
    }
    return 0;
}
© 版权声明
好牛新坐标
版权声明:
1、IT大王遵守相关法律法规,由于本站资源全部来源于网络程序/投稿,故资源量太大无法一一准确核实资源侵权的真实性;
2、出于传递信息之目的,故IT大王可能会误刊发损害或影响您的合法权益,请您积极与我们联系处理(所有内容不代表本站观点与立场);
3、因时间、精力有限,我们无法一一核实每一条消息的真实性,但我们会在发布之前尽最大努力来核实这些信息;
4、无论出于何种目的要求本站删除内容,您均需要提供根据国家版权局发布的示范格式
《要求删除或断开链接侵权网络内容的通知》:https://itdw.cn/ziliao/sfgs.pdf,
国家知识产权局《要求删除或断开链接侵权网络内容的通知》填写说明: http://www.ncac.gov.cn/chinacopyright/contents/12227/342400.shtml
未按照国家知识产权局格式通知一律不予处理;请按照此通知格式填写发至本站的邮箱 wl6@163.com

相关文章

没有相关内容!