题目链接:https://codeforces.com/gym/102028

B. Ultraman vs. Aodzilla and Bodzilla

题意:

两只怪兽,它们的生命和攻击分别为hpA,hpB,attA,attB,现在你要打败它们,第i回合你的攻击为i。问在承受伤害最少的前提下,攻击序列字典序最小是怎样的。攻击A就是A,攻击B就是B。最后输出承受的最小伤害和攻击序列。

 

题解:

最后的答案肯定是总回合最小时产生的,但是先打死谁不一定,答案就是两种情况的最小值。之后考虑贪心地构造攻击序列。

这里用了种很巧妙地方法吧,定义溢出伤害为最后一击多余出来的伤害。

我们先考虑先将A打死,然后打B的情况。这种字典序已经尽可能小的,只要保证回合数最小就行了。怎么判断回合数最小呢,设Ra为击败A时的溢出伤害,Rtot为最后一击时的溢出伤害(包含了A溢出的伤害),这里Rtot的计算方法参考代码,如果现在Ra > Rtot,说明如果不要A的溢出伤害,可能会多打一回合,那么这时就应该在某一回合打B,这里的位置我们选择尽可能后面的就是Ra(细节考虑一下)。

另外一种情况,我们就先尽可能地将前面的换成A,最后再来判断Rb和Rtot的关系,如果有Rb > Rtot(注意这里Rb会不断减小,因为我们换了一些操作),那么此时如果没有Rb就要多打一回合,设最后一次操作在第i回合,显然现在Rb < i + 1,直接攻击是攻击不了的。我们此时将最后一次操作撤销,将第i + Rb - Rtot次攻击置为A即可,这样也满足最优(A尽可能靠前并且回合数最小)。

细节可以琢磨一下。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int T;
ll ha, hb, atta, attb;
ll Get_sum(ll x) {
    return 1ll * x * (x + 1) / 2;
}
ll Get_round(ll x) {
    ll ans = 1;
    while(Get_sum(ans) < x) ans++;
    return ans ;
}
int main() {
    ios::sync_with_stdio(false) ;cin.tie(0) ;
    cin >> T;
    while(T--) {
        cin >> ha >> hb >> atta >> attb;
        ll ra = Get_round(ha), rb = Get_round(hb), rtot = Get_round(ha + hb);
        string res(rtot,'B') ;
        ll ans = min(atta * ra + attb * rtot , attb * rb + atta * rtot) ;
        if(atta * ra + attb * rtot == ans) {
            string cur(rtot,'A') ;
            for(int i = ra ; i < rtot ; i++) cur[i] = 'B' ;
            ll remain_a = Get_sum(ra) - ha , remain_tot = Get_sum(rtot) - ha - hb ;
            if(remain_a > remain_tot) {
                cur[remain_a - 1] = 'B' ;
            }
            res = min(res ,cur) ;
        }
        int last;
        if(attb * rb + atta * rtot == ans) {
            string cur(rtot,'B') ;
            for(int i = rb ; i < rtot; i++) cur[i] = 'A' ;
            ll remain_b = Get_sum(rb) - hb;
            ll remain = remain_b - Get_sum(rtot) + ha + hb;
            for(int i = 0; i < ra ; i++) {
                if(remain_b >= i + 1) {
                    cur[i] = 'A' ;
                    remain_b -= i + 1;
                    remain -= i + 1;
                    last = i ;
                }
            }
            if(remain > 0) {
                cur[last] = 'B';
                cur[last + remain] = 'A' ;
            }
            res = min(res, cur) ;
        }
        cout << ans << ' ' << res << '\n' ;
    }
    return 0 ;
}
View Code

相关文章:

  • 2021-09-15
  • 2021-07-27
  • 2022-02-24
  • 2022-12-23
  • 2021-10-23
  • 2021-05-28
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-11-12
  • 2022-12-23
  • 2021-05-31
  • 2021-12-28
  • 2021-06-06
相关资源
相似解决方案