Educational Codeforces Round 167 A~D题解

A. Catch the Coin

思路:由题目条件可知我们最好的前进办法就是向那个点的方向走 ( x + 1 , y + 1 ) (x+1, y+1) (x+1,y+1),等 x x x坐标与目标点一致时再只对 y y y进行操作。由于每移动一步 y y y的坐标都会减1(注意这里我们移动完了目标点才会移动),所以目标点的坐标最小为-1,否则从原点出发永远无法追上。

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

#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    int n;
    std::cin >> n;

    for (int i = 0; i < n; i++) {
        int x, y;
        std::cin >> x >> y;

        if (y >= -1) {
            std::cout << "YES\n";
        } else {
            std::cout << "NO\n";
        }
    }   
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t = 1;
    // std::cin >> t;

    while (t--) {
        solve();
    }
    return 0;
}

B. Substring and Subsequence

思路:首先我们要明白,子串一定是答案串的一部分,接下来,我们要找出最多有多少子序列中出现的字符在这个子串中出现过(注意必须保持顺序的一致性)记为 m x mx mx,然后 l e n ( a ) + l e n ( b ) − m x len(a) + len(b) - mx len(a)+len(b)mx即为答案。

时间复杂度: O ( ∣ a ∣ × ∣ b ∣ ) O(|a| \times |b|) O(a×b)

#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    std::string a, b;
    std::cin >> a >> b;

    int ans = 1E9;

    for (int p = 0; p < b.size(); p++) {
        int res = a.size();
        int k = 0;
        for (int i = 0; i < a.size() && p + k < b.size(); i++) {
            if (b[p + k] == a[i]) {
                k++;
            }
        }
        res += b.size() - k;
        ans = std::min(ans, res);
    }

    std::cout << ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t;
    std::cin >> t;

    while (t--) {
        solve();
    }
    return 0;
}

C. Two Movies

思路:对于 − 1 , 0 , 1 -1,0,1 1,0,1三种值,每个人对两部电影的评价如果不同我们肯定是要选评价更高的那个,答案一定更优。剩下的就是讨论每个人对于两部电影评价一致的情况,都是 0 0 0我们不需要考虑,因为对最终结果不造成影响。对 − 1 -1 1的情况,我们进行一个转化,即将当前两部电影的评分都 − 1 -1 1,然后将 − 1 -1 1的投票变为 1 1 1,这两种情况是等价的。所以也就是,最终我们只需要考虑正向投票的情况就好了。最终情况要么把票全投给一个人,要么两个人轮流给票,结果取最小值。

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

#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    int n;
    std::cin >> n;

    std::vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }

    for (int i = 0; i < n; i++) {
        std::cin >> b[i];
    }

    int sumA = 0, sumB = 0;
    int countPos = 0;
    for (int i = 0; i < n; i++) {
        if (a[i] != b[i]) {
            if (a[i] > b[i]) {
                sumA += a[i];
            } else {
                sumB += b[i];
            }
        } else {
            if (a[i] == -1) {
                sumA--;
                sumB--;
                countPos++;
            } else if (a[i] == 1) {
                countPos++;
            }
        }
    }

    int ans = std::min({sumA + countPos, sumB + countPos, (sumA + sumB + countPos) >> 1});

    std::cout << ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t;
    std::cin >> t;

    while (t--) {
        solve();
    }
    return 0;
}

D. Smithing Skill

思路:首先有一个比较显然的贪心就是,每次合成后立即融化掉可以得到2点经验值,同时也可以回收一部分材料,所以实际上我们只需要求最多可以合成多少次就好了。对于每一种合成的金属,实际上的代价为 a i − b i a_i - b_i aibi,所以我们肯定优先选择代价最小的金属进行合成。

根据数据范围,我们考虑对花费代价能合成的次数进行预处理,设 d p [ i ] dp[i] dp[i]为材料为 i i i时最多可以合成多少次,那么无论对于哪个 i i i,进行操作之后 i i i只会变小而不会变大,也就是说, d p [ i ] dp[i] dp[i]的求解仅依赖于之前的状态。在这之前我们需要先处理出材料为 i i i时最少需要花费多少材料能够进行一次合成,记为 f [ i ] f[i] f[i],于是 d p dp dp转移方程为 d p [ i ] = d p [ i − f [ i ] ] + 1 dp[i] = dp[i - f[i]] + 1 dp[i]=dp[if[i]]+1

然后只需要查表求解次数就好了。

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

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;

    int s = 0;
    std::vector<int> a(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
        s = std::max(s, a[i]);
    }

    std::vector<int> f(s + 1, s + 1);
    for (int i = 0; i < n; i++) {
        int b;
        std::cin >> b;

        f[a[i]] = std::min(f[a[i]], a[i] - b);
    }

    for (int i = 1; i <= s; i++) {
        f[i] = std::min(f[i], f[i - 1]);
    }

    std::vector<int> dp(s + 1);
    for (int i = 1; i <= s; i++) {
        if (f[i] <= i) {
            dp[i] = dp[i - f[i]] + 1;
        }
    }

    i64 ans = 0;
    while (m--) {
        int c;
        std::cin >> c;

        if (c > s) {
            int t = (c - s - 1 + f[s]) / f[s];
            ans += t;
            c -= t * f[s];
        }

        ans += dp[c];
    }

    std::cout << ans * 2 << "\n";
    return 0;
}
  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值