题解按照题目顺序排列

A题

知识点:模拟,优先队列
初始时,CPU为空,第一个进程进入后,对于第二进程的选择,会以下选择:
1.当当前进程运行结束时,第二进程仍未进入,此时直接输出即可
2.若不足,此时已经处理了从当前到第二进程进入时间差值,减去后重新加入优先队列
此时剩下que内的进程,直接按照优先级排列即可,因为剩下的要么是已经被处理过的,要么是即将处理的
都已经与出现时间无关了

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
struct node {
    i64 num, time, val, pri;
    bool operator>(const node& y) const {
        if (pri != y.pri) {
            return y.pri > pri;
        } else {
            return time > y.time;
        }
    }
};
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    priority_queue<node, vector<node>, greater<node>> que;
    vector<node> f;
    i64 a, b, c, d;
    i64 pre = 0;
    while (cin >> a >> b >> c >> d) {
        while (!que.empty() && pre + que.top().val <= b) {
            cout << que.top().num << " " << que.top().val + pre << "\n";
            pre += que.top().val;
            que.pop();
        }
        if (!que.empty()) {
            node x = que.top();
            que.pop();
            x.val = pre + x.val - b;
            que.push(x);
        }
        que.push({a, b, c, d});
        pre = b;
    }
    while (!que.empty()) {
        cout << que.top().num << " " << pre + que.top().val << "\n";
        pre += que.top().val;
        que.pop();
    }
    return 0;
}

B题

知识点:二分
没啥好讲的,注意y是实数

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
constexpr double eps = 1e-14;
void solve() {
    double y;
    cin >> y;
    double l = 0, r = 100;
    auto check = [&](double x) -> double { return 2018 * x * x * x * x + 21 * x + 5 * x * x * x + 5 * x * x + 14; };
    while (r - l > eps) {
        double mid = (l + r) / 2;
        if (check(mid) >= y) {
            r = mid;
        } else {
            l = mid;
        }
    }
    if (check(l) > y) {
        cout << -1 << '\n';
    } else {
        cout << fixed << setprecision(4) << l << "\n";
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

C题

知识点:前缀和
由于中位数要包括k,则考虑从数字k开始拓展
固定一边,处理大于k和小于k情况
此时遍历另一边,每次加上相反数量的情况个数即可\

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, k;
    cin >> n >> k;
    int mid = 0;
    vector<int> f(n + 1);
    map<int, int> mp;
    mp[0] = 1;
    for (int i = 1; i <= n; i++) {
        cin >> f[i];
        if (f[i] == k) {
            mid = i;
        }
    }
    int ans = 0;
    for (int i = mid - 1; i >= 1; i--) {
        ans += (f[i] > k) ? 1 : -1;
        mp[ans]++;
    }
    int res = mp[0];
    ans = 0;
    for (int i = mid + 1; i <= n; i++) {
        ans += (f[i] > k) ? 1 : -1;
        res += mp[-ans];
    }
    cout << res << "\n";
    return 0;
}

D题

知识点:字符串 先转化为相同大写,加密即将原文向右移动k-'A'位,解密则相反
故模拟即可,注意需要保留大小写情况,负数情况\

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    string a, b;
    cin >> a >> b;
    int n1 = a.size(), n2 = b.size();
    for (int i = 0; i < n2; i++) {
        char c = a[i % n1];
        if (c <= 'z' && c >= 'a') {
            c = c - 'a' + 'A';
        }
        char d = b[i];
        if (d <= 'z' && d >= 'a') {
            d = d - 'a' + 'A';
        }
        char res = ((d - 'A') - (c - 'A') + 26) % 26 + 'A';
        if (b[i] <= 'z' && b[i] >= 'a') {
            res = res - 'A' + 'a';
        }
        cout << res;
    }
    return 0;
}

E题

知识点:数学,模拟 由于k在1e5内,数据较大,在时间限制下,正常数据类型都无法存下,高精度无法在规定时间内完成
选择一些质数,计算输入的数模这些质数的值,再一个一个计算数列的每一项模这些质数的值,直到找到第一个完全一样的就是答案。
注意输入数据量较大,需要通过字符串来输入转化为数字,注意取模

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
using PII = pair<i64, i64>;
constexpr i64 MOD = 1e9 + 9;
constexpr int N = 1e5;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    vector<i64> f(N + 1);
    f[1] = 1;
    f[2] = 2;
    map<i64, i64> mp;
    mp[1] = 1, mp[2] = 2;
    for (int i = 3; i <= N; i++) {
        f[i] = (f[i - 1] + f[i - 2]) % MOD;
        mp[f[i]] = i;
    }
    string s;
    while (cin >> s) {
        i64 ans = 0;
        for (auto k : s) {
            ans = (ans * 10 % MOD + k - '0') % MOD;
        }
        cout << mp[ans] << '\n';
    }
    return 0;
}

F题

参考训练赛2H题,原题\

G题

知识点:数学 签到题

void solve() {
    int p, q;
    cin >> p >> q;
    if (p * q < 0) {
        cout << p / q - 1 << '\n';
    } else {
        cout << p / q - (p % q == 0) << "\n";
    }
}

H题

记录一下是不是每次都是复读即可
注意:由于题目问的是可能,所以未发言的都有可能是复读机

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vector<int> f(n + 1, -1);
    string pre = "";
    while (m--) {
        int op;
        string s;
        cin >> op >> s;
        if (s == pre && f[op] == -1) {
            f[op] = 1;
        }
        if (s != pre) {
            f[op] = 0;
        }
        pre = s;
    }
    vector<int> res;
    for (int i = 1; i <= n; i++) {
        if (f[i] == 1 || f[i]==-1) {
            cout << i << " ";
        }
    }
    return 0;
}

目录中的附加题 XOUR

知识点:位运算,并查集
需要异或后,由于异或相当于不进位加法,故保留除最后两位前的所有二进制位,其中4种皆与该数满足条件
故将一个数右移两位后,将所有情况加入并查集并从小到大排序,再按照祖宗依次输出即可

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
void solve() {
    int n;
    cin >> n;
    vector<i64> f(n + 1);
    map<i64, vector<i64>> mp;
    for (int i = 1; i <= n; i++) {
        cin >> f[i];
        mp[f[i] >> 2LL].push_back(f[i]);
    }
    map<i64, int> cnt;
    for (auto& [l, p] : mp) {
        cnt[l] = 0;
        sort(p.begin(), p.end());
    }
    for (int i = 1; i <= n; i++) {
        i64 t = f[i] >> 2LL;
        cout << mp[t][cnt[t]++] << " ";
    }
    cout << "\n";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}