【PAT】11 模拟

第十一章 模拟

AcWing 1480. 电梯

问题描述

分析

  • 记录上一次电梯所在的楼层last,然后根据当前所在的楼层cur更新用时。

  • 注意:每个停止的楼层都要消耗5s

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    int n;
    cin >> n;
    
    int res = 0;
    int last = 0;  // 上次停在的楼层
    for (int i = 0; i < n; i++) {
        int cur;
        cin >> cur;
        
        if (last < cur) res += (cur - last) * 6;
        else res += (last - cur) * 4;
        
        res += 5;
        last = cur;
    }
    
    cout << res << endl;
    
    return 0;
}

AcWing 1483. 世界杯投注

问题描述

分析

  • 本题相当于给一个3x3的矩阵,我们需要从每一行中选取一个最大的数,输出所在的列,最后将选出的三个数按照题目给出的公式计算利润。

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    double res = 1;
    for (int i = 0; i < 3; i++) {
        double w, t, l;
        cin >> w >> t >> l;
        double x = max(w, max(t, l));
        if (x == w) printf("W ");
        else if (x == t) printf("T ");
        else printf("L ");
        
        res *= x;
    }
    printf("%.2lf\n", (res * 0.65 - 1) * 2);
    
    return 0;
}

AcWing 1486. 排队等候

问题描述

分析

  • 银行有n个窗口,我们可以开n个队列模拟这n个窗口,队列中存储每个人的完成时间(相对于0,最后还要加上8)。

  • 每次新来一个人,我们如何将其插入队列中呢?可以另外使用一个数组sumsum[i]中记录了当前第i个队列所有人被服务结束的时间。

  • 首先我们找到新来的人需要插到的队列t,如果有未满的队列,找到第一个未满的队列,将新来的人插入,如果队列都是满的话,找到最先有一个人完成的队列,将新来的人插入队尾即可。

  • 对于在8:00~16:59之间来的人服务结束时间存入哈希表中,方便之后查询。

代码

  • C++
#include <iostream>
#include <queue>
#include <unordered_map>

using namespace std;

const int N = 20;

int n, m, k, Q;
queue<int> q[N];
int sum[N];

int main() {
    
    cin >> n >> m >> k >> Q;
    
    unordered_map<int, int> hash;
    for (int i = 1; i <= k; i++) {
        int s;
        cin >> s;  // 第i个人服务用时
        
        int t = 0;  // 找到第i个人应该插入到的队列t
        for (int j = 0; j < n; j++) {
            if (i <= n * m) {
                if (q[j].size() < q[t].size()) 
                    t = j;
            } else {
                if (q[j].front() < q[t].front())
                    t = j;
            }
        }
        
        sum[t] += s;
        if (i > n * m) q[t].pop();
        q[t].push(sum[t]);
        
        if (sum[t] - s < 540) hash[i] = sum[t];
    }
    
    while (Q--) {
        int id;
        cin >> id;
        if (hash.count(id)) printf("%02d:%02d\n", hash[id] / 60 + 8, hash[id] % 60);
        else puts("Sorry");
    }
    
    return 0;
}

AcWing 1515. U 形 Hello World

问题描述

分析

  • 根据题意可知:

{ n = n 1 + n 2 + n 3 − 2 n 1 = n 3 n 1 ≤ n 2 \begin{cases} n = n_1 + n_2 + n_3 - 2 \\ n_1 = n_3 \\ n_1 \le n_2 \end{cases} n=n1+n2+n32n1=n3n1n2

  • 根据 n 1 = n 3 n_1=n_3 n1=n3,可知 n = 2 n 1 + n 2 − 2 n=2n_1+n_2-2 n=2n1+n22,即 n 2 = n + 2 − 2 n 1 n_2 = n+2-2n_1 n2=n+22n1,带入最后一个不等式中,可以得到:

n 1 ≤ n + 2 3 n_1 \le \frac{n+2}{3} n13n+2

  • 因为要求 n 1 n_1 n1 最大,上式向下取整就是 n 1 n_1 n1的取值,然后就可以得到另外两个数的值。

  • 之后开一个二维数组,将对应的字母放置到对应的位置输出即可。

代码

  • C++
#include <iostream>

using namespace std;

const int N = 100;

char g[N][N];

int main() {
    
    string s;
    cin >> s;
    
    int n = s.size();
    int n1 = (n + 2) / 3;
    int n2 = n - 2 * n1 + 2;
    
    int k = 0;
    for (int i = 0; i < n1; i++) g[i][0] = s[k++];
    for (int i = 1; i < n2; i++) g[n1 - 1][i] = s[k++];
    for (int i = n1 - 2; i >= 0; i--) g[i][n2 - 1] = s[k++];
    
    for (int i = 0; i < n1; i++) {
        for (int j = 0; j < n2; j++) {
            if (g[i][j]) cout << g[i][j];
            else cout << ' ';
        }
        cout << endl;
    }
    
    return 0;
}

AcWing 1525. 独一无二

问题描述

分析

  • 两次遍历序列即可,第一次遍历统计出每个数字出现的次数,第二次遍历查看第一次出现一次的数字,如果不存在输出None即可。

代码

  • C++
#include <iostream>

using namespace std;

const int N = 100010;

int n;
int a[N], c[N];

int main() {
    
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
        c[a[i]]++;
    }
    
    for (int i = 0; i < n; i++)
        if (c[a[i]] == 1) {
            printf("%d\n", a[i]);
            return 0;
        }
    
    puts("None");
    
    return 0;
}

AcWing 1526. 洗牌机

问题描述

分析

  • 初始序列为1~54,每次根据打乱数组q进行洗牌,最终输出洗牌后的序列即可。

代码

  • C++
#include <iostream>
#include <cstring>

using namespace std;

const int N = 60;

int k;
// a: 初始序列; q: 洗牌序列; w: 缓存序列
int a[N], q[N], w[N];

void print(int x) {
    if (x <= 13) cout << 'S' << x;
    else if (x <= 26) cout << 'H' << x - 13;
    else if (x <= 39) cout << 'C' << x - 26;
    else if (x <= 52) cout << 'D' << x - 39;
    else cout << 'J' << x - 52;
}

int main() {
    
    cin >> k;
    for (int i = 1; i <= 54; i++) {
        scanf("%d", &q[i]);
        a[i] = i;
    }
    
    while (k--) {
        memcpy(w, a, sizeof a);
        for (int i = 1; i <= 54; i++) a[q[i]] = w[i];
    }
    
    for (int i = 1; i <= 54; i++) {
        print(a[i]);
        if (i != 54) cout << ' ';
    }
    
    return 0;
}

AcWing 1531. 课程学生列表

问题描述

分析

  • 使用数组记录每个课程对应的学生即可。

代码

  • C++
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 2510;

int n, k;
vector<string> lesson[N];

int main() {
    
    scanf("%d%d", &n, &k);
    char name[5];
    for (int i = 0; i < n; i++) {
        int cnt;
        scanf("%s%d", name, &cnt);
        while (cnt--) {
            int id;
            scanf("%d", &id);
            lesson[id].push_back(name);
        }
    }
    
    for (int i = 1; i <= k; i++) {
        printf("%d %d\n", i, lesson[i].size());
        sort(lesson[i].begin(), lesson[i].end());
        for (auto id : lesson[i])
            printf("%s\n", id.c_str());
    }
    
    return 0;
}

AcWing 1540. 主导颜色

问题描述

分析

  • 使用哈希表统计出现的次数,然后判断是否超过半数即可。

代码

  • C++
#include <iostream>
#include <unordered_map>

using namespace std;

int n, m;

int main() {
    
    scanf("%d%d", &n, &m);
    
    unordered_map<int, int> hash;  // (数据, 出现次数)
    for (int i = 0; i < n * m; i++) {
        int x;
        scanf("%d", &x);
        if (++hash[x] * 2 > n * m) {
            printf("%d\n", x);
            return 0;
        }
    }
    
    return 0;
}

AcWing 1542. 老鼠和大米

问题描述

分析

  • 按照题目模拟一遍即可。

  • 使用数组cur记录老鼠的顺序,cur[i] = j表示第j个老鼠排在位置i上,则根据本轮顺序计算下一轮剩余的老鼠next数组时,还需要存储每个老鼠的编号。

代码

  • C++
#include <iostream>
#include <vector>

using namespace std;

const int N = 1010;

int n, m;
int w[N], ans[N];

int main() {
    
    cin >> n >> m;
    for (int i = 0; i < n; i++) cin >> w[i];
    
    vector<int> cur(n);  // cur[i] = j表示第j个老鼠排在位置i上
    for (int i = 0; i < n; i++) cin >> cur[i];
    
    while (cur.size() > 1) {
        vector<int> next;
        int remain = (cur.size() + m - 1) / m;  // 本轮过后剩余的老鼠数量
        
        for (int i = 0; i < cur.size(); ) {
            int j = min((int)cur.size(), i + m);  // 考察区间[i, j)
            
            int t = i;
            for (int k = i; k < j; k++)
                if (w[cur[k]] > w[cur[t]])
                    t = k;
            next.push_back(cur[t]);  // 最重的老鼠下次还要比较
            for (int k = i; k < j; k++)
                if (k != t)
                    ans[cur[k]] = remain + 1;  // 不是本组中最重的老鼠的排名
            i = j;
        }
        cur = next;
    }
    
    ans[cur[0]] = 1;
    
    cout << ans[0];
    for (int i = 1; i < n; i++) cout << ' ' << ans[i];
    cout << endl;
    
    return 0;
}

AcWing 1548. 才华与德行

问题描述

分析

  • 本题是一个多关键字排序,首先根据人的类型排序,每种类型内部根据得分降序排序,如果得分相同根据品德降序排序,如果还相同,则根据名称升序排列。

代码

  • C++
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n, L, H;
struct Person {
    int id, moral, talent;  // ID,德行,才华
    int level;  // 1~4分别代表:圣人、君子、愚人、小人
    
    int total() const {
        return moral + talent;
    }
    
    bool operator< (const Person &t) const {
        if (level != t.level) return level < t.level;
        if (total() != t.total()) return total() > t.total();
        if (moral != t.moral) return moral > t.moral;
        return id < t.id;
    }
} p[N];

int main() {
    
    scanf("%d%d%d", &n, &L, &H);
    
    int cnt = 0;  // 记录需要排序的人数
    for (int i = 0; i < n; i++) {
        int id, moral, talent;
        scanf("%d%d%d", &id, &moral, &talent);
        
        if (moral < L || talent < L) continue;
        
        int level;
        if (moral >= H && talent >= H) level = 1;
        else if (moral >= H && talent < H) level = 2;
        else if (moral < H && talent < H && moral >= talent) level = 3;
        else level = 4;
        
        p[cnt++] = {id, moral, talent, level};
    }
    
    sort(p, p + cnt);
    
    printf("%d\n", cnt);
    for (int i = 0; i < cnt; i++)
        printf("%d %d %d\n", p[i].id, p[i].moral, p[i].talent);
    
    return 0;
}

AcWing 1551. A + B 和 C

问题描述

分析

  • 本题考察数据在计算机中的表示。

  • 两个正数相加的话如果溢出则会变为负数,此时a+b一定是大于c的;两个负数相加的话如果溢出则会变为非负数(可能为0,当两个数都是最小的负数时),此时a+b一定是小于c的。

  • 最后如果不溢出的话,直接计算a+bc进行比较即可。

代码

  • C++
#include <iostream>

using namespace std;

typedef long long LL;

bool check(LL a, LL b, LL c) {
    
    LL t = a + b;
    if (a > 0 && b > 0 && t < 0) return true;
    if (a < 0 && b < 0 && t >= 0) return false;
    return a  + b > c;
}

int main() {
    
    int T;
    cin >> T;
    
    for (int C = 1; C <= T; C++) {
        LL a, b, c;
        scanf("%lld%lld%lld", &a, &b, &c);  // 不能用cin, PAT最后
        printf("Case #%d: ", C);
        if (check(a, b, c)) puts("true");
        else puts("false");
    }
    
    return 0;
}

AcWing 1555. 数字黑洞

问题描述

分析

  • 按照题目要求进行模拟即可。

代码

  • C++
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> get(int n) {
    int nums[4];
    for (int i = 0; i < 4; i++) nums[i] = n % 10, n /= 10;
    
    sort(nums, nums + 4);
    
    int a = 0;
    for (int i = 0; i < 4; i++) a = a * 10 + nums[i];
    
    reverse(nums, nums + 4);
    int b = 0;
    for (int i = 0; i < 4; i++) b = b * 10 + nums[i];
    
    return {b, a};
}

int main() {
    
    int n;
    cin >> n;
    
    do {
        auto t = get(n);
        printf("%04d - %04d = %04d\n", t[0], t[1], t[0] - t[1]);
        n = t[0] - t[1];
    } while (n != 0 && n != 6174);
    
    return 0;
}

AcWing 1566. 研究生入学

问题描述

分析

  • 本题只需要考虑每个人被录取到哪个大学即可,不需要考虑录取到哪个大学的哪个专业。

  • 使用结构体存储每个同学,然后根据分数进行降序排序。然后依次考察每个分数段同学(要求这些同学的分数完全相同)。

  • 每次需要一次性考虑每个分数段的同学,这是因为可能有很多成绩完全相同的同学报同一所大学,但录取一部分人就到达招生人数,这种情况下需要将所有学生招到该校(即使超过招生限额)。

代码

  • C++
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 40010, M = 110, K = 5;

int n, m, k;
int cnt[M];  // 每所大学招生的人数
int wish[N];  // 记录每个人哪个志愿可以成功, wish[t]=w代表:大学t可以录取学生t
vector<int> uty[M];  // 记录大学录取的人

struct Person {
    int id, ge, gi;
    int wish[K];  // 该学生的志愿
    
    int total() const {
        return ge + gi;
    }
    
    bool operator< (const Person &t) const {
        if (total() != t.total()) return total() > t.total();
        return ge > t.ge;
    }
    
    bool operator== (const Person &t) const {
        return ge == t.ge && gi == t.gi;
    }
} p[N];

int main() {
    
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < m; i++) scanf("%d", &cnt[i]);
    for (int i = 0; i < n; i++) {
        p[i].id = i;
        scanf("%d%d", &p[i].ge, &p[i].gi);
        for (int j = 0; j < k; j++)
            scanf("%d", &p[i].wish[j]);  // 第i个人的第j个志愿
    }
    
    sort(p, p + n);
    
    memset(wish, -1, sizeof wish);
    for (int i = 0; i < n; ) {
        // 找到分数相同的所有人[i, j)
        int j = i + 1;
        while (j < n && p[i] == p[j]) j++;
        
        // 一起考虑这些人可以分别被哪个志愿录取
        for (int t = i; t < j; t++)
            for (int u = 0; u < k; u++) {
                int w = p[t].wish[u];  // 考虑第t个人的第u个志愿
                if (cnt[w] > uty[w].size()) {  // 说明大学w可以录取第t个人
                    wish[t] = w;
                    break;
                }
            }
        
        // 录取
        for (int t = i; t < j; t++)
            if (wish[t] != -1)
                uty[wish[t]].push_back(p[t].id);
        
        i = j;
    }
    
    // 依次输出大学的录取结果
    for (int i = 0; i < m; i++) {
        if (uty[i].size()) {
            sort(uty[i].begin(), uty[i].end());
            printf("%d", uty[i][0]);
            for (int j = 1; j < uty[i].size(); j++) printf(" %d", uty[i][j]);
        }
        puts("");
    }
    
    return 0;
}

AcWing 1569. 成绩单

问题描述

分析

  • 将每个学生存入结构体中,然后根据降序排序。

  • 之后从前遍历所有学生,判断其成绩是否在给定范围内,如果在给定范围内,输出即可。

代码

  • C++
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n;
int g1, g2;

struct Person {
    string name, id;
    int grade;
    
    bool operator< (const Person &t) const {
        return grade > t.grade;
    }
} p[N];

int main() {
    
    cin >> n;
    for (int i = 0; i < n; i++) cin >> p[i].name >> p[i].id >> p[i].grade;
    
    sort(p, p + n);
    
    cin >> g1 >> g2;
    int cnt = 0;
    for (int i = 0; i < n; i++)
        if (p[i].grade >= g1 && p[i].grade <= g2) {
            cout << p[i].name << ' ' << p[i].id << endl;
            cnt++;
        }
    
    if (!cnt) puts("NONE");
    
    return 0;
}

AcWing 1582. 买还是不买

问题描述

分析

  • 本题相当于给定我们一个目标串b,然后给定我们另一个串a,问a中是否完全包含b(顺序无所谓)?

  • 可以使用一个哈希表S,首先统计a中每个字符出现的次数,然后减去b中每个字符出现的次数。之后遍历S,如果S中有字符出现次数为负数的话,说明a不能完全包含b

代码

  • C++
#include <iostream>
#include <unordered_map>

using namespace std;

int main() {
    
    string a, b;
    cin >> a >> b;
    
    unordered_map<char, int> S;
    for (auto c : a) S[c]++;
    for (auto c : b) S[c]--;
    
    int sp = 0, sn = 0;
    for (auto item : S) 
        if (item.second > 0) sp += item.second;
        else sn -= item.second;
    
    if (sn) printf("No %d\n", sn);
    else printf("Yes %d\n", sp);
    
    return 0;
}

AcWing 1585. 校园内的汽车

问题描述

分析

  • 每辆汽车都会对应很多事件,因此可以使用哈希表存储每辆车对应的事件。

  • 之后对于每辆车将所有事件排序,并和合法事件保留,非法事件直接删除。

  • 对于题目中的每个询问,我们可以将所有合法事件存放到一个容器events中,并按时间排序,因为询问时间是递增的,因此可以在上一次查询的基础上继续查询,只要当前考察的事件的时间小于查询时间,我们就考虑该事件,如果是车进入校园,则让车辆数sum加一,否则减一。

  • 对于在校停留时间最长的车辆,我们首先找出停留的最长时间maxt,然后找出所有停留时间等于maxt的所有车辆,排序后输出即可。

代码

  • C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>

using namespace std;

int n, m;

struct Event {
    int tm, status;  // tm:时间; status: 0表示in, 1表示out
    
    bool operator< (const Event &t) {
        return tm < t.tm;
    }
};

// 返回汽车car在校内停留的总时间
int get(vector<Event> &car) {
    
    int res = 0;
    for (int i = 0; i < car.size(); i += 2)
        res += car[i + 1].tm - car[i].tm;
    
    return res;
}

int main() {
    
    scanf("%d%d", &n, &m);
    
    unordered_map<string, vector<Event>> cars;
    char id[10], status[5];
    for (int i = 0; i < n; i++) {
        int hh, mm, ss;
        scanf("%s %d:%d:%d %s", id, &hh, &mm, &ss, status);
        int s = 0;
        if (status[0] == 'o') s = 1;
        cars[id].push_back({hh * 3600 + mm * 60 + ss, s});
    }
    
    vector<Event> events;  // 所有合法事件
    for (auto &item : cars) {
        auto  &ets = item.second;
        sort(ets.begin(), ets.end());
        
        int k = 0;
        for (int i = 0; i < ets.size(); i++)
            if (ets[i].status == 0) {
                if (i + 1 < ets.size() && ets[i + 1].status == 1) {  // in的下一个时间必须是out才合法
                    ets[k++] = ets[i];
                    ets[k++] = ets[i + 1];
                    i++;
                }
            }
        ets.erase(ets.begin() + k, ets.end());  // 非法事件直接删除
        for (int i = 0; i < ets.size(); i++) events.push_back(ets[i]);
    }
    
    // 求解每个时刻校园内停车的汽车总数
    sort(events.begin(), events.end());
    int k = 0, sum = 0;  // sum: 当前在学校内的车的数量
    while (m--) {
        int hh, mm, ss;
        scanf("%d:%d:%d", &hh, &mm, &ss);
        int t = hh * 3600 + mm * 60 + ss;
        while (k < events.size() && events[k].tm <= t) {
            if (events[k].status == 0) sum++;
            else sum--;
            k++;
        }
        
        printf("%d\n", sum);
    }
    
    // 求解停车时间最长的汽车的车牌号,以及相应的时间长度
    int maxt = 0;
    for (auto &car : cars) maxt = max(maxt, get(car.second));
    
    vector<string> res;
    for (auto &item : cars)
        if (get(item.second) == maxt)
            res.push_back(item.first);
    
    sort(res.begin(), res.end());
    
    for (int i = 0; i < res.size(); i++) printf("%s ", res[i].c_str());
    
    printf("%02d:%02d:%02d\n", maxt / 3600, maxt % 3600 / 60, maxt % 60);
    
    return 0;
}

AcWing 1595. 螺旋矩阵

问题描述

分析

  • 首先枚举出合法的行数列数r、c,然后将数组降序排序,最后将数据填到数组中即可。

  • 螺旋数组需要使用到偏移量技巧。

代码

  • C++
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 10010;

int n;
int w[N];

int main() {
    
    cin >> n;
    for (int i = 0; i < n; i++) cin >> w[i];
    
    sort(w, w + n, greater<int>());
    
    int r, c;
    for (int i = 1; i <= n / i; i++)
        if (n % i == 0) {
            r = n / i;
            c = i;
        }
    
    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
    vector<vector<int>> res(r, vector<int>(c, 0));
    for (int i = 0, x = 0, y = 0, d = 1; i < n; i++) {
        res[x][y] = w[i];
        int a = x + dx[d], b = y + dy[d];
        if (a < 0 || a >= r || b < 0 || b >= c || res[a][b]) {
            d = (d + 1) % 4;
            a = x + dx[d], b = y + dy[d];
        }
        x = a, y = b;
    }
    
    for (int i = 0; i < r; i++) {
        cout << res[i][0];
        for (int j = 1; j < c; j++) cout << ' ' << res[i][j];
        cout << endl;
    }
    
    return 0;
}

AcWing 1599. 合影

问题描述

分析

  • 从最后一行开始输出,最后一行的元素可能多于前面的元素个数。

  • 首先对所有的0人进行排序,然后按照题目要求进行模拟即可。

代码

  • C++
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10010;

int n, m;

struct Person {
    string name;
    int h;
    
    bool operator< (const Person &t) const {
        if (h != t.h) return h > t.h;
        return name < t.name;
    }
} p[N];
string line[N];

int main() {
    
    cin >> n >> m;
    for (int i = 0; i < n; i++) cin >> p[i].name >> p[i].h;
    
    sort(p, p + n);
    
    for (int i = 0, j = 0; i < m; i++) {  // i枚举每一行,j枚举每个人
        int len = n / m;
        if (!i) len += n % m;  // 特判最后一排
        for (int r = len / 2 + 1, l = r - 1; r <= len || l > 0; r++, l--) {
            if (r <= len) line[r] = p[j++].name;
            if (l > 0) line[l] = p[j++].name;
        }
        
        cout << line[1];
        for (int i = 2; i <= len; i++) cout << ' ' << line[i];
        cout << endl;
    }
    
    return 0;
}

AcWing 1614. 单身狗

问题描述

分析

  • 首先使用哈希表统计所有派对的人,然后遍历所有的伴侣,如果一对伴侣都在哈希表中存在,则将伴侣两个人都从哈希表删除,最后剩余的就是单身狗。

代码

  • C++
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>

using namespace std;

const int N = 50010, M = 10010;

int n, m;
struct Couple {
    int a, b;
} c[N];
int ans[M];

int main() {
    
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d%d", &c[i].a, &c[i].b);
    
    scanf("%d", &m);
    unordered_set<int> S;
    for (int i = 0; i < m; i++) {
        int x;
        scanf("%d", &x);
        S.insert(x);
    }
    
    for (int i = 0; i < n; i++) {
        int a = c[i].a, b = c[i].b;
        if (S.count(a) && S.count(b)) {
            S.erase(a);
            S.erase(b);
        }
    }
    
    int k = 0;
    for (auto x : S) ans[k++] = x;
    sort(ans, ans + k);
    
    printf("%d\n", k);
    
    if (k) {
        printf("%05d", ans[0]);
        for (int i = 1; i < k; i++) printf(" %05d", ans[i]);
        puts("");
    }
    
    
    return 0;
}

AcWing 1621. N 皇后问题

问题描述

分析

  • 本题中给出了每列中皇后的位置,因此列中皇后不可能重复,需要判断行、主对角线方向(右上到左下)、副对角线是否存在两个皇后,可以使用数组row、dg、udg分别记录这些方向是否已经放置过皇后,从而判断是否存在矛盾即可。

代码

  • C++
#include <iostream>
#include <cstring>

using namespace std;

const int N = 1010;

int n;
bool row[N], dg[N * 2], udg[N * 2];

int main() {
    
    int T;
    scanf("%d", &T);
    
    while (T--) {
        scanf("%d", &n);
        
        memset(row, 0, sizeof row);
        memset(dg, 0, sizeof dg);
        memset(udg, 0, sizeof udg);
        
        bool success = true;
        for (int y = 1; y <= n; y++) {
            int x;
            scanf("%d", &x);
            if (row[x] || dg[x + y] || udg[x - y + n]) success = false;
            row[x] = dg[x + y] = udg[x - y + n] = true;
        }
        
        if (success) puts("YES");
        else puts("NO");
    }
    
    return 0;
}

AcWing 1622. 推荐系统

问题描述

分析

  • 本题需要在用户访问过的物品中选出访问次数最多的k个物品进行输出。

  • 因为k最大为10,可以开辟一个长度为11的数组top_k记录出现次数最多的前k个商品,然后输出。

  • 当用户又访问一个商品时,如果这个商品不在top_k中 出现,则将其加到top_k最后的位置(当top_k存放的商品满了之后直接放到最后一个位置即可),然后重新排序输出出现最多的前k个商品。如果这个商品在top_k中,则排序后输出即可。

代码

  • C++
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 50010;

int n, m;
int cnt[N];  // 统计每个商品被访问次数,用于排序
int top_k[11];

int main() {
    
    scanf("%d%d", &n, &m);
    
    int k = 0;  // top_k中放入的物品数
    for (int i = 0; i < n; i++) {
        int id;
        scanf("%d", &id);
        
        if (i) {
            printf("%d:", id);
            for (int j = 0; j < k; j++) printf(" %d", top_k[j]);
            puts("");
        }
        
        cnt[id]++;
        
        bool exists = false;
        for (int j = 0; j < k; j++)
            if (top_k[j] == id) {
                exists = true;
                break;
            }
        if (!exists) top_k[k++] = id;
        sort(top_k, top_k + k, [](int x, int y){
            if (cnt[x] != cnt[y]) return cnt[x] > cnt[y];
            return x < y;
        });
        
        k = min(k, m);
    }
    
    return 0;
}

AcWing 1625. 切整数

问题描述

分析

  • 直接按照题目要求进行验证即可。

  • 一个小技巧:因为需要对整数切分,可以以字符串行书读入数据,然后切分后转成整数即可。

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    int T;
    cin >> T;
    while (T--) {
        string s;
        cin >> s;
        
        int len = s.size() / 2;
        int a = stoi(s.substr(0, len));
        int b = stoi(s.substr(len));
        int c = stoi(s);
        
        if (a * b != 0 && c % (a * b) == 0) puts("Yes");
        else puts("No");
    }
    
    return 0;
}

AcWing 1633. 外观数列

问题描述

分析

代码

  • C++
#include <iostream>

using namespace std;

int main() {
    
    int d, n;
    cin >> d >> n;
    
    string cur = to_string(d);
    for (int k = 0; k < n - 1; k++) {
        string next;
        for (int i = 0; i < cur.size(); i++) {
            int j = i + 1;
            while (j < cur.size() && cur[j] == cur[i]) j++;
            next += cur[i] + to_string(j - i);
            i = j - 1;
        }
        cur = next;
    }
    
    cout << cur << endl;
    
    return 0;
}

AcWing 1640. 堆

问题描述

分析

  • 使用数组存储堆即可,堆顶元素在下标为1的位置。然后根据判断是否存在根节点大于子节点,或者子节点大于根节点。

  • 如果上述两者都存在,说明不是堆,否则根据两者哪个成立确定是大顶堆还是小顶堆。

代码

  • C++
#include <iostream>

using namespace std;

const int N = 1010;

int n;
int h[N];  // 存储堆

void dfs(int u) {
    
    if (u * 2 <= n) dfs(u * 2);
    if (u * 2 + 1 <= n) dfs(u * 2 + 1);
    
    printf("%d", h[u]);
    if (u != 1) cout << ' ';
}

int main() {
    
    int T;
    scanf("%d%d", &T, &n);
    
    while (T--) {
        
        for (int i = 1; i <= n; i++) scanf("%d", &h[i]);
        
        bool lt = false, gt = false;
        for (int i = 1; i <= n; i++)
            for (int j = 0; j <= 1; j++)
                    if (2 * i + j <= n) {
                        int a = h[i], b = h[2 * i + j];  // b是a的儿子
                        if (a > b) gt = true;
                        else lt = true;
                    }
        
        if (lt && gt) puts("Not Heap");
        else if (lt) puts("Min Heap");
        else puts("Max Heap");
        
        dfs(1);  // 后续遍历
        puts("");
    }
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值