​LINK​

找到最小的 n n n满足 ∑ i = 1 n i > = h p a + h p b \sum\limits_{i=1}^ni>=hp_a+hp_b i=1∑ni>=hpa+hpb

可以证明,在 n n n轮对决中打死两个怪物一定是最优的(因为可以选择先打死 A A A或先打死 B B B)

定义 p r e i = ∑ j = 1 i j pre_i=\sum\limits_{j=1}^i j prei=j=1∑ij

考虑如果先打死 A A A

找到最小的 p 1 p_1 p1满足 p r e p 1 > = h p a pre_{p_1}>=hp_a prep1>=hpa,前 p 1 p_1 p1次都打 A A A,后面都打 B B B

①.若此时 p r e n − p r e p 1 > = h p b pre_n-pre_{p_1}>=hp_b pren−prep1>=hpb,保留此方案.已经满足字典序最小

②.若此时 p r e n − p r e p 1 < h p b pre_n-pre_{p_1}<hp_b pren−prep1<hpb,说明之前打 A A A浪费了一些攻击力

需要把某次对 A A A的攻击转移到攻击 B B B去,而且需要满足攻击的尽量晚(字典序最小)

于是我们在第 p r e p 1 − h p a pre_{p_1}-hp_a prep1−hpa个回合去打 B B B即可,这样仍然是刚好打完 A A A,且 字典序最小

考虑如果先打死 B B B

找到最小的 p 1 p_1 p1满足 p r e p 1 > = h p b pre_{p_1}>=hp_b prep1>=hpb,前 p 1 p_1 p1次都打 B B B,后面都打 A A A

考虑第 p 1 p_1 p1次攻击溢出了 p r e p 1 − h p b pre_{p_1}-hp_b prep1−hpb的伤害,可以将前面若干次攻击替换给 A A A

不妨二分到一个最大的点使得 p r e p 2 < = p r e p 1 − h p b pre_{p_2}<=pre_{p_1}-hp_b prep2<=prep1−hpb

这样前 p 2 p_2 p2次攻击都打 A A A,之后一直打 B B B直到打死,再一直打 A A A

①.若 p r e n < h p a + h p b + ( p r e p 1 − h p b − p r e p 2 ) pre_{n}<hp_a+hp_b+(pre_{p_1}-hp_b-pre_{p_2}) pren<hpa+hpb+(prep1−hpb−prep2)

也就是 p r e n + p r e p 2 > = h p a + p r e p 1 pre_n+pre_{p_2}>=hp_a+pre_{p_1} pren+prep2>=hpa+prep1,可以在剩余时间内打掉 A A A,确定此方案为最终方案

②.否则,还是浪费的太多了,我们至少应该再有 z = h p a + p r e p 1 − p r e n − p r e p 2 z=hp_a+pre_{p_1}-pre_n-pre_{p_2} z=hpa+prep1−pren−prep2点数值去攻击 A A A

于是我们不在第 p 2 p_2 p2次攻击 B B B,而是在第 p 2 + z p_2+z p2+z次攻击 B B B,这样仍然满足字典序最小(因为刚好打死)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 3e5+10;
int pre[maxn];
char ans1[maxn],ans2[maxn];
int hpa,hpb,ata,atb,n;
void solve1()//先打A
{
int p1 = lower_bound( pre+1,pre+1+64000,hpa )-pre;
for(int i=1;i<=p1;i++) ans1[i] = 'A';
for(int i=p1+1;i<=n;i++) ans1[i] = 'B';
if( pre[n]-pre[p1]>=hpb ) return;//已经是最优解
int z = pre[p1]-hpa;//溢出的伤害
ans1[z] = 'B';
}
void solve2()
{
int p1 = lower_bound( pre+1,pre+1+64000,hpb )-pre;
int p2 = upper_bound( pre+1,pre+1+64000,pre[p1]-hpb )-pre-1;
int p3 = lower_bound( pre+1,pre+1+64000,hpa )-pre;
p2 = min( p3,p2 );
for(int i=1;i<=p2;i++) ans2[i] = 'A';
for(int i=p2+1;i<=p1;i++) ans2[i] = 'B';
for(int i=p1+1;i<=n;i++) ans2[i] = 'A';
if( pre[n]+pre[p2]>=hpa+pre[p1] ) return;
int z = hpa+pre[p1]-pre[n]-pre[p2];
ans2[p2] = 'B'; ans2[p2+z] = 'A';
}
int get(char ans[],int hpa,int hpb)
{
int res = 0;
for(int i=1;i<=n;i++)
{
if( hpa>0 ) res += ata;
if( hpb>0 ) res += atb;
if( ans[i]=='A' ) hpa -= i;
if( ans[i]=='B' ) hpb -= i;
}
return res;
}
bool xcompare(char ans1[],char ans2[])
{
for(int i=1;i<=n;i++)
if( ans1[i]<ans2[i] ) return true;
else if( ans1[i]>ans2[i] ) return false;
return true;
}
void print(int x,char ans[] )
{
cout << x << " ";
for(int i=1;i<=n;i++) cout << ans[i];
cout << endl;
}
signed main()
{
for(int i=1;i<=64000;i++) pre[i] = pre[i-1]+i;
int T; cin >> T;
while( T-- )
{
cin >> hpa >> hpb >> ata >> atb;
n = lower_bound( pre+1,pre+1+64000,hpa+hpb )-pre;//最早结束的回合数
solve1(); solve2();
int x = get( ans1,hpa,hpb ), y = get( ans2,hpa,hpb );
// print(x,ans1); print(y,ans2);
if( x<y || ( x==y && xcompare(ans1,ans2) ) ) print( x,ans1 );
else print( y,ans2 );
}
}