题解 「EZEC-6」游戏
-
subtask 1
略
-
subtask 2
最优轮数为
-
subtask 3
设
设
初始
总时间复杂度为
-
subtask 4
使用 bitset 优化 subtask3 的做法,复杂度
-
subtask 5
设
在数据较大时,通过
考虑在
分类讨论并整合后可以得到,当
若最优轮数为
若最优轮数为
钦定
之后使用和 subtask4 相同的做法,但是只需要计算前
对于小数据,可以直接采用 subtask4 的做法。
经实践,
注意,如果实现时 bitset 定长,则复杂度错误,为 bitset 可以达到正确的复杂度,如果不手写 bitset 通过调节阈值或设置多个阈值也可以通过。
-
subtask 6
以下同样基于数据较大。
设
考虑直接构造求解,设
因为
这些情况已经涵盖了所有 subtask5 对最优轮数的讨论 甚至还多了一些,在大数据下一定可以找到方案,时间复杂度为
接下来讨论这个做法的适用数据范围,在关于最优轮数的结论成立的情况下,只要保证
在运算过程中多次把下界往大算,所以这个界非常松,但是没必要卡得更紧了,实际的下界约为
做法不适用时,使用 subtask4 的算法即可,此处增加的运算次数最多为
忽略上述常数,总复杂度为
实现时,倒推可以
code:
#include<bits/stdc++.h>
using namespace std;
#define N 20000005
#define M 529
int read(){
int w=0,f=1;
char c=' ';
while(c<'0'||c>'9')c=getchar(),f=c=='-'?-1:f;
while(c>='0'&&c<='9')w=w*10+c-48,c=getchar();
return w*f;
}
int n,m,s,flag;
char ans[N];
bitset<M>f[M],base;
void get(int x,int y){
if(!x)return;
if(y-x>=0)
if(f[x-1][y-x]){
get(x-1,y-x);
ans[x]='A';
return;
}
if(y+x<=n+m)
if(f[x-1][y+x]){
get(x-1,y+x);
ans[x]='B';
return;
}
}
void brute(){
base.reset();
for(int i=0;i<=n+m;i++)
base[i]=1;
f[0].reset();
f[0][n]=1;
for(int i=1;i<=n+m;i++)
f[i]=(f[i-1]<<i|f[i-1]>>i)&base;
for(int i=n+m;i>=0;i--){
if(!f[i].any())continue;
int x=0;
for(int j=0;j<=n+m&&!x;j++)
if(f[i][j])x=j;
printf("%d\n",i);
get(i,x);
puts(ans+1);
memset(ans+1,0,sizeof(char)*i);
return;
}
}
void add(int&x,int&y){
ans[y]='A',x+=y,y++;
}
void sub(int&x,int&y){
ans[y]='B',x-=y,y++;
}
void solve(int c,int f,int op){
if(flag)return;
int now=1,x=n,t=op&1?n+m-f:f;
if(op&1)t-=(n+m-c-s)/2;
else t+=(n+m-c-s)/2;
if((n+m-c-s)&1){
if((n+m-c-s-1+op)&1)t-=s+1;
else t+=s+1;
}
while(x>=now)sub(x,now);
if(op<=1){
while(x+now<=t)add(x,now);
while(x<t)sub(x,now),add(x,now);
}
else{
while(x<=t)add(x,now);
while(x>t)add(x,now),sub(x,now);
}
while(now<=s)sub(x,now),add(x,now),add(x,now),sub(x,now);
if(now!=s+1)return;
flag=1;
for(int i=n+m-c;i>s;i--)
if((n+m-c-i+op)&1)ans[i]='A';
else ans[i]='B';
printf("%d\n",n+m-c);
puts(ans+1);
memset(ans+1,0,sizeof(char)*(n+m-c));
}
signed main(){
int T=read();
while(T--){
n=read(),m=read(),flag=0;
if(n+m<M){
brute();
continue;
}
s=6*ceil(sqrt(n+m));
if(((n-m)%4+4)%4==2){
for(int i=0;i<4;i++)
for(int k=0;k<2;k++)
solve(1,k,i);
}
else{
for(int i=0;i<4;i++)
solve(0,0,i);
}
}
return 0;
}