Practice.

A. New Scheme

题意

给定一个长度为 \(8\) 的序列 \(S\),判断是否满足下面的条件:

  1. 不递减

  2. \(100 \leq S_i \leq 675\)

  3. \(25\) 的倍数

思路

如题

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define psi pair<string, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;

void solve() {
    vector<int> s(8);
    for(int i=0;i<8;i++) cin >> s[i];
    for(int i=0;i<7;i++){
        if(s[i] > s[i + 1]){
            cout << "No\n";
            return;
        }
    }
    for(auto e : s){
        if(e % 25 != 0 || e < 100 || e > 675){
            cout << "No\n";
            return;
        }
    }
    cout << "Yes\n";
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t --) solve();
}

如题

B. Default Price

题意

给定 \(m\) 种菜品名称,以及对应的价格 \(p_i\),未给菜品价格为 \(p_0\)

现在,给定 \(n\) 个菜品,输出总价。

思路

\(map\) 存一下即可。

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

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define psi pair<string, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;

void solve() {
    int n, m;
    cin >> n >> m;
    map<string, int> p;
    vector<string> a(n);
    vector<string> b(m);
    for(int i=0;i<n;i++) cin >> a[i];
    for(int i=0;i<m;i++) cin >> b[i];
    int x;
    cin >> x;
    for(int i=0;i<m;i++) {
        int cur;
        cin >> cur;
        p[b[i]] = cur;
    }
    int ans = 0;
    for(auto e : a) {
        if(p.count(e)) ans += p[e];
        else ans += x;
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t --) solve();
}

如题

C. Standings

题意

给定序列 \(X = \{1, 2, 3, \ldots,n\}\),以及两个长为 \(n\) 的序列 \(A, B\),按照下面的方式排序 \(X\) 后输出:

  1. 主关键字:\(\frac{A_i}{A_i + B_i}\),降序;

  2. 次关键字:\(X_i\) 的值,升序

思路

这题是估计卡精度的,对于 \(\frac{A_x}{A_x + B_x} \leq \frac{A_y}{A_y + B_y}\),移项得 \(A_x(A_y + B_y) \leq A_y(A_x + B_x)\)

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

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define psi pair<string, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;;
const double eps = 1e-19;

void solve() {
    int n;
    cin >> n;
    vector<int> c(n);
    for(int i=0;i<n;i++) c[i] = i;
    vector<int> a(n), b(n);
    for(int i=0;i<n;i++){
        cin >> a[i] >> b[i];
    }
    sort(all(c), [&](int o1, int o2) -> bool{
        return (__int128)a[o1] * (a[o2] + b[o2]) == (__int128)a[o2] * (a[o1] + b[o1]) ? o1 < o2 : (__int128)a[o1] * (a[o2] + b[o2]) > (__int128)a[o2] * (a[o1] + b[o1]);
    });
    for(auto e: c) cout << e + 1 << ' ';
    cout << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t --) solve();
}

有被坑到,谢谢

D. Snuke Maze

题意

给定由 \(s, n, u, k, e\) 组成的大小为 \(H \times W\) 的矩阵,判断是否存在一条从 \((1, 1)\)\((H, W)\) 的路径,路径中的第 \(i\) 个元素为字符串 \(snuke\) 的第 \(((i - 1)\mod 5) + 1\) 个字符。

思路

\(\mathtt{dfs}\) 即可,不过不需要回溯。

时间复杂度:\(O(nm)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define psi pair<string, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;;
const double eps = 1e-19;

void solve() {
    int h, w;
    cin >> h >> w;
    vector<string> a(h);
    for(int i=0;i<h;i++) cin >> a[i];
    vector<vector<bool>> ok(h, vector<bool>(w));
    vector<pii> to = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    string s = "snuke";
    bool f = false;
    auto dfs = [&](auto dfs, int x, int y, int st) -> void{
        if(f) return;
        if(x == h - 1 && y == w - 1){
            cout << "Yes\n";
            f = true;
            return;
        }
        for(auto [dx, dy] : to){
            int tx = x + dx, ty = y + dy;
            if(tx >= 0 && ty >= 0 && tx < h && ty < w && !ok[tx][ty] && s[(st + 1) % 5] == a[tx][ty]){
                ok[tx][ty] = true;
                dfs(dfs, tx, ty, st + 1);
            }
        }
    };
    ok[0][0] = true;
    dfs(dfs, 0, 0, 0);
    if(!f) cout << "No\n";
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t --) solve();
}

最近怎么老是因为回溯 \(tle\)

E. MEX

题意

给定一个长为 \(n\) 且只包含 \(0, 1, 2\) 的序列 \(A\) 以及 一个长为 \(n\) 且只包含 \(M, E, X\) 的字符串 \(S\)

对于所有长度为 \(3\) 的子序列(不一定连续)\(S_1S_2S_3\),输出所有拼接后为 \(MEX\) 的字符串对应的 \(mex(A_1, A_2, A_3)\)

其中,\(mex(x, y, z)\) 表示非负数中不等于 \(x, y, z\) 中的最小值。

思路

假设 \(E\) 的位置固定,那么如果我们知道前面有 \(x\)\(M\)\(y\)\(X\),以这个 \(E\) 为中心的子序列 \(MEX\) 个数即可根据乘法原理算得:\(xy\)

那么照这个思路,因为考虑重复时 \(0, 1, 2\) 总共有 \(27\) 种放置方式,我们直接分讨即可。

举个例子,如果对于第 \(i\) 个位置,该位置为 \(E\),且 \(A_i = 0\),并且前面有 \(pre[0]\)\(M\) 对应的 \(A\) 序列中的值为 \(0\), 后面有 \(suf[1]\)\(X\) 对应的 \(A\) 序列中的值为 \(1\),那么这个情况对应的答案为 \(2 \times pre[0] \times suf[1]\)

那么,我们用两个二维数组分别维护前缀和后缀个数即可。

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define psi pair<string, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;;
const double eps = 1e-19;

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for(int i=1;i<=n;i++) cin >> a[i];
    string s;
    cin >> s;
    s = "#" + s;
    vector<vector<int>> pre(n + 1, vector<int>(3));
    vector<vector<int>> suf(n + 2, vector<int>(3));
    for(int i=1;i<=n;i++){
        for(int j=0;j<3;j++) pre[i][j] = pre[i - 1][j];
        if(s[i] == 'M') pre[i][a[i]] ++;
    }
    for(int i=n;i>= 1;i--){
        for(int j=0;j<3;j++) suf[i][j] = suf[i + 1][j];
        if(s[i] == 'X') suf[i][a[i]] ++;
    }
    int ans = 0;
    for(int i=1;i<=n;i++){
        if(s[i] != 'E') continue;
        if(a[i] == 0){//000 001 011 002 022 012
            ans += 1 * pre[i][0] * suf[i][0];
            ans += 2 * (pre[i][0] * suf[i][1] + pre[i][1] * suf[i][0]);
            ans += 2 * pre[i][1] * suf[i][1];
            ans += 1 * (pre[i][0] * suf[i][2] + pre[i][2] * suf[i][0]);
            ans += 1 * pre[i][2] * suf[i][2];
            ans += 3 * (pre[i][1] * suf[i][2] + pre[i][2] * suf[i][1]);
        }else if(a[i] == 1){
            ans += 2 * pre[i][0] * suf[i][0];
            ans += 2 * (pre[i][0] * suf[i][1] + pre[i][1] * suf[i][0]);
            ans += 0 * pre[i][1] * suf[i][1];
            ans += 3 * (pre[i][0] * suf[i][2] + pre[i][2] * suf[i][0]);
            ans += 0 * pre[i][2] * suf[i][2];
            ans += 0 * (pre[i][1] * suf[i][2] + pre[i][2] * suf[i][1]);
        }else{
            ans += 1 * pre[i][0] * suf[i][0];
            ans += 3 * (pre[i][0] * suf[i][1] + pre[i][1] * suf[i][0]);
            ans += 0 * pre[i][1] * suf[i][1];
            ans += 1 * (pre[i][0] * suf[i][2] + pre[i][2] * suf[i][0]);
            ans += 0 * pre[i][2] * suf[i][2];
            ans += 0 * (pre[i][1] * suf[i][2] + pre[i][2] * suf[i][1]);
        }
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t --) solve();
}

就是写起来像依托史

F. Vouchers

题意

给定 \(n\) 个标价为 \(P_i\) 的商品,以及 \(m\) 个满 \(D_i\)\(L_i\) 的券,在每一种券只能使用一次 并且 不能叠加使用 的条件下,输出购买所有商品需要的最小金额。

思路

简单贪心。

我们肯定希望能尽可能使用折扣力度大一点的券,那么对于某一个商品,我们就使用能使用的减价最多的券。

当然,我们也希望券能用多一点,所以我们按照商品的价格升序排序,然后依次使用能使用的减价最多的券。

上述贪心思路是显然正确的,而具体实现方式可以为优先队列。

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

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define ppii pair<int, pii>
#define psi pair<string, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 1e9 + 7, inf = 0x3f3f3f3f3f3f3f3f;;
const double eps = 1e-19;

void solve() {
    int n, m;
    cin >> n >> m;
    vector<int> p(n);
    vector<pii> v(m);
    int ans = 0;
    for(int i=0;i<n;i++) cin >> p[i], ans += p[i];
    for(int i=0;i<m;i++) cin >> v[i].fs;
    for(int i=0;i<m;i++) cin >> v[i].sc;
    sort(all(p)), sort(all(v));
    int st = 0;
    priority_queue<int> q;
    for(int i=0;i<n;i++){
        while(st < m && v[st].fs <= p[i]) q.emplace(v[st ++].sc);
        if(!q.empty()) ans -= q.top(), q.pop();
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t --) solve();
}

居然在 \(F\) 放签到