本题解借鉴了某大佬的博客,由于那篇博客里有点小错误,因此我这里重写一篇,希望大家在看到我的博客的同时也关注一下那位大佬。
大佬博客地址
题解思路:很显然,要使奥特曼受到的伤害最小,肯定要先杀死一只怪兽,所以我们就分类讨论先杀A还是先杀B。
//不少人可能会说比较一下A,B的攻击力,先杀攻击力高的一定会更优。但这是错误的,比如一个100血10攻的怪和一只3血9攻的怪,显然是要先杀3血9攻的那只怪。
因此,我们就分类先杀A还是先杀B,然后比较两者的耗费和字典序,取最小即可。
首先处理一个前缀和的数组pri[i]表示1到i时刻的伤害总和。
1.先杀A
我们先算出最快打死A的回合:u1=lower_bound(pri+1,pri+100000,a.H)-pri
打死两个怪的最快时间:u2=lower_bound(pri+1,pri+100000,a.H+b.H)-pri
(1)哪怕不分A溢出的伤害,剩下的伤害也足以在u2-u1回合内打死B
这样肯定是1-u1是A,u1+1到u2是B字典序最小。
(2)pri[u2]-pri[u1]<b.H
在这种情况下,A溢出的伤害必然要打到B上,那应该在那一次打呢?自然是尽可能靠后,B越靠后字典序越小。
2.先杀B
算出最快打死B的回合:u1=lower_bound(pri+1,pri+100000,b.H)-pri
先杀B分伤害给A的情况处理起来就比较麻烦,因为要使A尽可能靠前,这里最好的情况就是在伤害值<=B溢出伤害时前面能插入一段连续的A,然后这段的伤害+pri[u2]-pri[u1]>=a.H,这样能保证B先死且A尽可能地靠前。可是如果不行呢,我们就只能把前面连续的A拆出来,往后移,让对A的伤害值变大,这样才能打死两只怪兽。
(1)一段A的前缀+pri[u2]-pri[u1]>=a.H
(2)在上述情况打不死的情况下,定义left=a.H-(pri[u2]-pri[u1]) (前面那部分所需要造成的伤害)。在1-u1的回合,当left>=2*i+1 || left==i 的时候插入A,left -= i,否则插入B,剩下的全是A。
#include<bits/stdc++.h> using namespace std; #define maxn 300005 #define ll long long const int mod = 1e9 + 7; int T; ll pri[maxn]; struct node{ ll H,K; }a,b; void init(){ for(int i=1;i<=1e5;i++) pri[i]=pri[i-1]+i; } int main() { init(); scanf("%d",&T); while(T--){ ll suma=0,sumb=0; string ansa,ansb; scanf("%lld %lld %lld %lld",&a.H,&b.H,&a.K,&b.K); //A先死- int u1=lower_bound(pri+1,pri+100000,a.H)-pri; int u2=lower_bound(pri+1,pri+100000,b.H+a.H)-pri; ll left=pri[u1]-a.H; suma=a.K*u1+b.K*u2; if(pri[u2]-pri[u1]>=b.H){ for(int i=1;i<=u1;i++) ansa+='A'; for(int i=u1+1;i<=u2;i++) ansa+='B'; } else{ for(int i=1;i<=u1;i++){ if(i==left)ansa+='B'; else ansa+='A'; } for(int i=u1+1;i<=u2;i++) ansa+='B'; } //B先死 u1=lower_bound(pri+1,pri+100000,b.H)-pri; u2=lower_bound(pri+1,pri+100000,a.H+b.H)-pri; sumb=b.K*u1+a.K*u2; left=pri[u1]-b.H; int pos=upper_bound(pri+1,pri+100000,left)-pri-1; if(pri[pos]+pri[u2]-pri[u1]>=a.H){ for(int i=1;i<=pos;i++) ansb+='A'; for(int i=pos+1;i<=u1;i++) ansb+='B'; for(int i=u1+1;i<=u2;i++) ansb+='A'; } else{ left=a.H-(pri[u2]-pri[u1]); for(int i=1;i<=u1;i++){ if(left>=2*i+1||left==i){ left-=i; ansb+='A'; } else ansb+='B'; } for(int i=u1+1;i<=u2;i++) ansb+='A'; } if(suma<sumb)cout<<suma<<" "<<ansa<<" "; else if(sumb<suma)cout<<sumb<<" "<<ansb<<" "; else{ if(ansa<ansb)cout<<suma<<" "<<ansa<<" "; else cout<<sumb<<" "<<ansb<<" "; } } return 0; }