2023年7月6日普及组南外集训题解

A 阿伦

因为相邻的穿同样衣服的人只要走了一个就会全走,所以我们可以定义一个char数组,只要当前的与上一个不同,答案就加一

#include <iostream>
using namespace std;

int main() {
    int n, ans = 0;
    char c0 = ' ', c1;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> c1;
        if (c0 != c1)
            ans++;
        c0 = c1;
    }
    cout << ans + 1;
    return 0;
}

B 二八杠

由于本题需要判断的东西非常多,非常容易遗漏,如果使用常用的if else可能会有遗漏导致错误,所以我们可以给每种操作赋一个权值,这样在判断是就会非常方便,但是要注意关于权值的问题

注:\((x+y)\%10*10\)的原因是因为\(x,y\)的和的个位数有可能小于原本的数

#include <iostream>
using namespace std;
int cal(int x, int y) {
    if (x > y)
        swap(x, y);
    if (x == 2 && y == 8)
        return 1000;
    else if (x == y)
        return 900;
    else
        return (x + y) % 10 * 10 + y;
}
int main() {
    int n;
    cin >> n;
    while (n--) {
        int a1, a2, b1, b2;
        cin >> a1 >> a2 >> b1 >> b2;
        if (cal(a1, a2) == cal(b1, b2))
            puts("tie");
        else if (cal(a1, a2) > cal(b1, b2))
            puts("first");
        else
            puts("second");
    }
    return 0;
}

C 编程考试

我们可以使用前缀和优化这个问题,首先开一个二维数组,存储每个位置上的字母,用string读入,注意string的下标是从0开始的

#include <iostream>
using namespace std;
int word_count[50005][26];
string s;
int q;
int main() {
    cin >> s;
    for (int i = 1; i <= s.length() - 1; i++) {
        for (int j = 0; j < 26; j++) {
            word_count[i][j] = word_count[i - 1][j];
        }
        word_count[i][s[i - 1] - 'a']++;
    }
    cin >> q;
    while (q--) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        bool flag = true;
        for (int i = 0; i < 26; i++) {
            if (word_count[b][i] - word_count[a - 1][i] != word_count[d][i] - word_count[c - 1][i]) {
                flag = false;
                break;
            }
        }
        puts(flag ? "DA" : "NE");
    }
    return 0;
}

D 01反转

首先我们可以先定义一个数组,意在获得连续的一段数字有几个,这样可减低我们的时间复杂度

接下来我们将这个数组进行累加,两个之间夹着的就是我们的答案,我们要先判断一下是从0还是1开始,如果是1,遍历的时候i要加一

我们的数组要另开2*k个,原因如下图:

#include <iostream>
#include <cstring>
using namespace std;
const int M = 2e5 + 7;
int n, k, cnt = 0, pre[M], ans = 0;
string s;

int main() {
    cin >> n >> k;
    cin >> s;
    pre[++cnt] = 1;
    for (int i = 1; i < n; i++) {
        if (s[i] != s[i - 1])
            pre[++cnt] = 1;
        else
            pre[cnt]++;
    }
    for (int i = 1; i <= cnt + 2 * k; i++) pre[i] += pre[i - 1];
    int i = 0 + ((s[0] - '0') == 1);
    while (i <= cnt) {
        ans = max(ans, pre[i + 2 * k] - pre[i - 1]);
        i += 2;
    }
    cout << ans;
    return 0;
}

E 愉悦的晚餐

这个问题\(n\)的范围很大,用dfs或二进制枚举只能拿到50%的分,所以我们要进行优化

进过枚举我们可以发现值的排列一共有8种,这对于我们后面求绝对值有帮助

之后我们根据初中数学可以得知,绝对值的结果分为两种,之后我们便可简单解答

如下图:

所以我们算的时候直接分8种:

calc(1, 1, -1);
calc(1, -1, -1);
calc(1, -1, 1);
calc(1, 1, 1);
calc(-1, 1, 1);
calc(-1, -1, 1);
calc(-1, -1, -1);
calc(-1, 1, -1);
#include <bits/stdc++.h>
using namespace std;

long long n, m, a[1005], b[1005], c[1005], s[1005];
long long ans = -1e15;
bool cmp(long long x, long long y) { return x > y; }
void calc(int af, int bf, int cf) {
    long long ret = 0;
    for (int i = 1; i <= n; i++) {
        s[i] = af * a[i] + bf * b[i] + cf * c[i];
    }
    sort(s + 1, s + n + 1, cmp);
    for (int i = 1; i <= m; i++) ret += s[i];
    ans = max(ans, ret);
}
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i] >> b[i] >> c[i];
    }
    calc(1, 1, -1);
    calc(1, -1, -1);
    calc(1, -1, 1);
    calc(1, 1, 1);
    calc(-1, 1, 1);
    calc(-1, -1, 1);
    calc(-1, -1, -1);
    calc(-1, 1, -1);
    cout << ans;
    return 0;
}

F 买蛋糕

首先我们用暴力是解决不了这个问题的,我们要优美地解决

考虑到最终答案要求我们从大到小输出,我们自然就能想到优先队列的大根堆

这样最大值就直接输出根就可以了

另外我们需要定义一个结构体方便我们的存储,并在里面重载运算符,否则会导致stl的使用报错

bool operator < (const cake &A) const
{
	return a[x]+b[y]+c[z]<a[A.x]+b[A.y]+c[A.z];
}

关于优先队列如何使用可以参考 c++优先队列(priority_queue)用法详解

排序完之后便开始输出答案,首先输出根部,然后再进行拓展,分别是\(x+1,y+1,z+1\),记得用map打上标记,以免重复

#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
using namespace std;
const int N = 1e3 + 10;
long long a[N], b[N], c[N];
int x, y, z, k;
struct cake {
    int x, y, z;
    bool operator<(const cake &A) const { return a[x] + b[y] + c[z] < a[A.x] + b[A.y] + c[A.z]; }
};
priority_queue<cake> q;
map<pair<pair<int, int>, int>, bool> mp;
bool cmp(long long a, long long b) { return a > b; }
int main() {
    scanf("%d%d%d%d", &x, &y, &z, &k);
    for (int i = 1; i <= x; i++) cin >> a[i];
    for (int i = 1; i <= y; i++) cin >> b[i];
    for (int i = 1; i <= z; i++) cin >> c[i];
    sort(a + 1, a + x + 1, cmp);
    sort(b + 1, b + x + 1, cmp);
    sort(c + 1, c + x + 1, cmp);
    q.push((cake){ 1, 1, 1 });
    mp[make_pair(make_pair(1, 1), 1)] = true;
    for (int i = 1; i <= k; i++) {
        cake t = q.top();
        q.pop();
        printf("%lld\n", a[t.x] + b[t.y] + c[t.z]);
        if (!mp.count(make_pair(make_pair(t.x + 1, t.y), t.z)) && t.x < x) {
            mp[make_pair(make_pair(t.x + 1, t.y), t.z)] = true;
            q.push((cake){ t.x + 1, t.y, t.z });
        }
        if (!mp.count(make_pair(make_pair(t.x, t.y + 1), t.z)) && t.y < y) {
            mp[make_pair(make_pair(t.x, t.y + 1), t.z)] = true;
            q.push((cake){ t.x, t.y + 1, t.z });
        }
        if (!mp.count(make_pair(make_pair(t.x, t.y), t.z + 1)) && t.z < z) {
            mp[make_pair(make_pair(t.x, t.y), t.z + 1)] = true;
            q.push((cake){ t.x, t.y, t.z + 1 });
        }
    }
    return 0;
}
posted @ 2023-07-11 10:01  typerxiaozhu  阅读(55)  评论(0编辑  收藏  举报