q<=1000个询问,每次问a,b,c,d:f(a,b)表示含a个A,b个B的字符串中,连续A或连续B最小的串中,字典序最小的一个串,输出这个串的c到d位。a,b<=5e8,d-c+1<=100。
首先可以确定这个“连续A或连续B的最小值”是:$left lceil frac{p}{q+1} ight ceil$
然后就尽可能在前面放A,如果放A导致后面不满足这个“连续A或连续B的最小值”,就放B,这样是O(n)的。
打几个表发现:串实际上是前面:AA……ABAA……ABAA……ABAA……这样的,后面是BABB……BABB……BABB,这样的,那二分一下这个分界的位置,判断按前缀那样放A,B之后后缀能否满足“连续A或连续B的最小值”。然后根据c,d在这个位置前后分下类输出答案即可。
1 #include<string.h> 2 #include<stdlib.h> 3 #include<stdio.h> 4 #include<math.h> 5 //#include<assert.h> 6 #include<algorithm> 7 //#include<iostream> 8 //#include<bitset> 9 using namespace std; 10 11 int q,a,b,c,d,len; 12 13 int calc(int a,int b) 14 { 15 if (!a || !b) return a^b; 16 if (a<b) a^=b,b^=a,a^=b; 17 return (a-1)/(b+1)+1; 18 } 19 20 bool check(int x) 21 { 22 int cnta=x/(len+1)*len+x%(len+1),cntb=x/(len+1)-(x%(len+1)==0); 23 if (cnta>a) return 0; 24 return calc(a-cnta,b-cntb)<=len; 25 } 26 27 void workleft(int left,int right) 28 { 29 for (int i=left;i<=right;i++) 30 { 31 if (i%(len+1)==0) putchar('B'); 32 else putchar('A'); 33 } 34 } 35 void workright(int left,int right) 36 { 37 for (int i=left;i<=right;i++) 38 { 39 if ((a+b-i+1)%(len+1)==0) putchar('A'); 40 else putchar('B'); 41 } 42 } 43 44 int main() 45 { 46 scanf("%d",&q); 47 while (q--) 48 { 49 scanf("%d%d%d%d",&a,&b,&c,&d); 50 len=calc(a,b); 51 int L=0,R=a+b; 52 while (L<R) 53 { 54 int mid=(L+R+1)>>1; 55 if (check(mid)) L=mid; 56 else R=mid-1; 57 } 58 int pos=L; 59 if (d<=pos) workleft(c,d); 60 else if (c>pos) workright(c,d); 61 else workleft(c,pos),workright(pos+1,d); 62 puts(""); 63 } 64 return 0; 65 }