Ultraman vs. Aodzilla and Bodzilla(贪心)

题目

Six months ago our hero, formerly known as Huriyyah, was beating all monsters in the land. Now he changed his name to Ultraman and left his beloved land. He is ready to take on a new challenge.

In a remote land, local citizens are suffering from the harassment of two powerful and horrible monsters: Aodzilla and Bodzilla. They eat small children who go out alone and even kill innocent persons. The apprehension of being attacked has overwhelmed people for several decades.

For the good of these unfortunate citizens, Ultraman sets out for the forest which is the main lair of Aodzilla and Bodzilla. In the forest, he faces these two fierce and cruel monsters and fights with them. The health points of Aodzilla and Bodzilla are HPA
and HPB respectively, and their attack values are ATKA and ATKB

respectively.

They fight in a cave through turn-based battles. During each second, the Ultraman will be attacked by monsters at first, and the damage is the sum of attack values of all alive monsters. Then he will select exactly one monster which is still alive and attack it. The selected monster will suffer a damage of value i
(i.e. its health point will be decreased by i) where i represents that Ultraman has launched i attacks in total, from the beginning to the present, to these two monsters (and the current attack is the i-th one). That is to say, during the 1-st second, one of these two monsters will be under an attack of damage 1, during the 2-nd second, one of them, if alive, will be under an attack of damage 2, during the 3-rd second, one of them, if alive, will be under an attack of damage 3

, and so on. If at some time, the health point of a monster is less than or equal to zero, it will die immediately. The Ultraman will win if both monsters have been killed.

Now, you are asked to develop a strategy to minimize the total damage Ultraman should suffer before he wins the battle. A strategy can be described as a string whose length is the total time that the battle will last. The i
-th character in the string is ‘A’, if the Ultraman chooses to attack Aodzilla during the i-th second; otherwise, the i

-th character is ‘B’, which means Bodzilla will be the target during that second. You are also asked to find the optimal strategy whose string description is the smallest in lexicographical order among all possible optimal strategies.

For two distinct strings s
and t, if one string is a prefix of the other, then the one with a shorter length is smaller in lexicographical order. In other cases, s is smaller than t in lexicographical order if the first character of s is smaller than the first character of t, or in case they are equivalent, the second character of s is smaller than the second character of t, etc. The case t is smaller than s

in lexicographical order is defined similarly as the former case.
Input

The input contains several test cases, and the first line contains a positive integer T
indicating the number of test cases which is up to 105

.

For each test case, the only one line contains four integers HPA
, HPB, ATKA and ATKB, where 1≤HPA,HPB,ATKA,ATKB≤109.

We guarantee that there are at most 100
test cases with max{HPA,HPB}>103 .
Output

For each test case, output a line containing an integer indicating the minimal total damage Ultraman should suffer, and a string describing the optimal strategy such that the string description is the smallest in lexicographical order among all possible optimal strategies. You should output exactly one whitespace between the number and the string.
Example
Input

2
5 15 5 25
5 15 25 5

Output

155 BBBBBA
105 AAABBB

解释

两只怪兽已知攻击血量,要打死两只怪兽,让自身受到尽量少的伤害,且攻击序列要求字典序小的。那么就是在不影响最小自身所受伤害的前提下尽可能先攻击A。由于自身攻击力每回合加一,当到第i轮时,输出的总伤害是(1+i)*i/2。
现在考虑如何快点打死两只怪兽且自身所受伤害最小。两只怪兽肯定是要尽快打死一只,已知攻击血量,但具体如何衡量先攻击哪只比较好还是很难有个标准,所以考虑两种情况,分别尽快击杀其中一只,从这两种情况取所受伤害小的哪一种。
假设先击杀A,pha+phb,pha二分在自身输出伤害数组里查询,得出打死两只与先打死A的最少轮数i , j。但实际情况伤害可能是不够的,打A的时候最后一击可能是伤害溢出的。所以我们要考虑两种情况:1,如果打死两只的总伤害num[i] - A的最少轮数j所造成的伤害num[j]是大于等于phb,说明伤害是够的。无论打A的时候伤害溢出了没,都不计较了,因为A的字典序要求在前。 2、如果上述伤害是小于phb的话,说明A溢出伤害了,导致剩余伤害不够打死B。j是打A的最后一击伤害,而伤害溢出了,说明溢出伤害必然小于j,而伤害总量本来是够打死AB的,现在B缺少了伤害,但我们是不清楚B缺了多少。但是考虑到字典序最小,那么补给B的缺少伤害以一轮的形式补给B,选择溢出的伤害时,字典序最小。
假设先杀死B,其实本来应该和先杀A是没区别的,但是由于字典序的关系,细节上要再处理。我们也先分成以最少轮打死B后剩余伤害够不够打死A的两中情况。1、够打死A,但考虑到字典序最小,所以我们把B溢出伤害的部分尽可能给A(放心A这样不会提前被打死。轮数不变,因为最小轮数是以两者血量和来算的,不可能更小),比如溢出伤害7,我们选择第1,2,3轮都是打A。(余下点的伤害无所谓了,A本来伤害就够打死了(B的溢出伤害给A只会导致A的溢出伤害增多,总轮数不变),尽量把字典序变小是关键)
当剩余伤害不够打死A时,我们对B溢出伤害的处理分为两种:B的溢出伤害从1+2…+k加出来的小于B的溢出伤害的最大伤害是不是加上剩余伤害够打死A了?1、够的话 ,那么前k轮都打A,然后打死B,然后打死A(其实这种情况与伤害够打死B的结果是一样的),2、不够打死A的话,那么计算出A缺少的伤害(不是B溢出的伤害,因为拆分出来的数必然不连续了,要字典序最小,而A缺少的伤害比B溢出的伤害要小或者等于,而一个数越小拆分成多个不相同的数字典序越小,所以选择A缺少的伤害)要按照(lefta -i>i || lefta == i)的条件来拆分。

一开始我们是按照先打死某一只来分类的,对于先打死B的情况,是按照先打死A的剩余伤害够不够打死另一只的两种情况,按照字典序要求进行细节调整。但是我们发现在先打死B的两中情况的子情况,可以重新合并,变成(B的溢出伤害从1+2…+k加出来的小于B的溢出伤害的最大伤害是不是加上剩余伤害够打死A了?)。 但不重新合并逻辑上结果上也是对的,无伤大雅,自行选择吧。

关于程序代码里使用lower_bound ,upper_bound都是有原因的,lower_bound查找大于等于我们要找的数,这里的upper_bound是查找大于我们要找的数,而减一之后,就是查找小于等于我们要找的数(是为了找溢出伤害尽量拆成1、2、3…的情况,用lower的话找不到等于的就会是大的了,与我们的要求不符)。

#include 
#include 
#include 
#include 
#define ll long long
#define n 100001
using namespace std;
ll num[n];
int main(){
    int t;
    ll pha,phb,atka,atkb, i, pos, pos2, last;
    ll ansa, ansb, left, lefta;
    num[0] = 0;
    num[1] = 1;
    for(i = 2; i < n; i++)
        num[i] = num[i-1]+i;
    scanf("%d", &t);
    while(t--){
        string sta, stb;
        scanf("%lld%lld%lld%lld", &pha, &phb, &atka, &atkb);
        last = lower_bound(num, num+n, pha+phb) - num;
        pos =  lower_bound(num, num+n, pha) - num;
        ansa = last*atkb + pos*atka;
        if(num[last] - num[pos] >= phb){
            for(i = 1; i <= pos; i++)
                sta += 'A';
        }
        else{
            left = num[pos] - pha;
            for(i = 1; i <= pos; i++){
                if(i != left)
                    sta += 'A';
                else
                    sta += 'B';
            }
        }
        for(i = pos+1; i <= last; i++)
                sta += 'B';
        pos =  lower_bound(num, num+n, phb) - num;
        ansb = last*atka + pos*atkb;
        left = num[pos] - phb;
        pos2 = upper_bound(num, num+n, left) - num-1;
        if(num[last] - num[pos]+num[pos2] >= pha){
            for(i = 1; i <= pos2; i++)
                stb += 'A';
            for(i = pos2+1; i <= pos; i++)
                stb += 'B';
        }
        else{
            lefta = pha - (num[last] - num[pos]);
            for(i = 1; i <= pos; i++){
                if(lefta -i>i || lefta == i){
                        stb += 'A';
                        lefta -= i;
                }
                else
                        stb += 'B';
            }
        }
        for(i = pos+1; i <= last; i++)
            stb += 'A';
        if(ansa < ansb)
            printf("%lld ", ansa),cout << sta< ansb)
            printf("%lld ", ansb),cout << stb<

你可能感兴趣的:(Ultraman vs. Aodzilla and Bodzilla(贪心))