Codeforces Round #821 (Div. 2) D2、E

D2. Zero-One (Hard Version)

由题意可知相邻两个翻转代价x,不相邻两个翻转代价为y,首先考虑不可能将a变成b的情况,奇数个位置不同一定不能完成,其次考虑y如果不大于x的话,当不同的个数=2且这两个不同的位置紧邻,看到n>=5,所以一定可以用两个y替代一个x代价,所以比较2*y和x的大小,其余因为y的代价更小,一定能全用y代价把所有的都翻转,最后考虑y大于x的情况

DP,最大代价一定是全用y,考虑如果其中某几对位置相邻的用x的话比纯用y少了多少代价,设dp[i]为截止i和i+1,用y比用x的代价最多多了多少,所以cost记录的是i和i+1之间用y比用x代价多了多少,因为pos的下标是0base,所以当i==0的时候,要么用cost要么用y,因为这里算的是用y比用x多了多少代价,所以cost和0取max,当i==1的时候要么i和i+1取更优的cost,要么什么都不做,dp[i]=dp[i-1],说明截止i-1和i代价更优,当i>1,这时考虑什么都不做dp[i]=dp[i-1],或者dp[i-2]+cost,即截止i-2和i-1的代价+i和i+1的代价,最后只需要用最多的价值-所有用x时多余的代价

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin >> T;
    while (T--) {
        int n;
        LL x, y;
        cin >> n >> x >> y;
        string s1, s2;
        cin >> s1 >> s2;
        vector<LL> pos;
        for (int i = 0; i < n; i++) {
            if (s1[i] != s2[i]) {
                pos.push_back(i);
            }
        }
        LL len = pos.size();
        if (len % 2 == 1) {
            cout << "-1\n";
        } else if (y <= x) {
            if (len == 2 and pos[0] + 1 == pos[1]) {
                cout << min(x, 2 * y) << '\n';
            } else {
                cout << y * len / 2 << '\n';
            }
        } else {
            vector<LL> dp(len + 1);
            for (int i = 0; i < len - 1; i++) {
                LL cost = y - x * (pos[i + 1] - pos[i]);
                if (i == 0) {
                    dp[i] = max(0LL, cost);
                } else if (i == 1) {
                    dp[i] = max(dp[i - 1], cost);
                } else {
                    dp[i] = max(dp[i - 1], dp[i - 2] + cost);
                }
            }
            cout << y * len / 2 - dp[len - 2] << '\n';
        }
    }
    return 0;
}

E. Conveyor

由题知,直接判断第t秒(x,y)有没有球很难,根据数据范围一定要找到某个规律,发现可以考虑第i秒(x,y)经过了多少次球,要判断第t秒(x,y)有没有球就转化成第t秒(x,y)经过球的数量和第t-1秒(x,y)经过球的数量是否相等,因为箭头一开始都是先走右,再走下,所以转移的时候右侧的应为此时经过(i,j)小球数量的一半的上取整,走下侧的是此时经过(i,j)小球数量的一半的下取整,注意要判断t秒内能否有球到达(x,y),因为判断的时候是从0秒到t-x-y+1秒之间的小球才可能到达(x,y),后面的小球虽然也有,但一定都无法到达(x,y)

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin >> T;
    while (T--) {
        LL t, x, y;
        cin >> t >> x >> y;
        function<bool(LL)> f = [&](LL p) {
            vector<vector<LL>> dp(125, vector<LL> (125));
            dp[0][0] = max(0LL, p - x - y + 1);
            for (int i = 0; i <= 120; i++) {
                for (int j = 0; j <= 120; j++) {
                    dp[i][j + 1] += (dp[i][j] + 1) / 2;
                    dp[i + 1][j] += dp[i][j] / 2;
                }
            }
            return (dp[x][y] & 1);
        };
        if (f(t) != f(t - 1)) {
            cout << "YES\n";
        } else {
            cout << "NO\n";
        }
    }
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值