[AGC020D] Min Max Repetition

发布时间 2023-12-16 16:06:01作者: blueparrot

牛子题

优先满足第二个条件,长度是 \(\lceil \frac{max(A,B)}{min(A,B)+1}\rceil\) ,那么现在要满足字典序最小,发现先填 \(A..ABA..ABA..AB..\) ,中途可能 \(B>>A\) 就填不满 ,就要改变策略,变成 \(B..BAB..BA...\) 这样子的,但是注意可能 \(B\) 有余数,那我肯定优先把有余数个 \(B\) ,这样子肯定字典序小一点,然后二分两种方式的分界点, \(check\) 的话直接判断 \(shengB\times len \leq shengA\) 就行了

关于 \(check\) 的写法,为什么这样是对的?先考虑普通情况,正确性显然,但是如果 \(shengB \times len = shengA\) ,说明没有余数,那就是先填 \(A\) ,那万一之前最后一个也是 \(A\) , 就会寄掉,但是其实我们可以调整一下,把最后的 \(B\) 调整一个过来,把第二段的 \(A\) 给第一段,就是合法的了,本质上是分界点向右移动了,所以对于这种情况要返回 \(true\) 才行,不然答案会错

然后注意二分要像下面的代码那么写才不会错

#include<bits/stdc++.h>
#define il inline 
#define int long long
using namespace std;
il int read(){
	char c;int x=0,f=0;
	while(!isdigit(c=getchar()))f|=(c=='-');
	while(isdigit(c))x=(x*10)+(c^48),c=getchar();
	return f?-x:x;
}
int A,B,C,D,len;
il bool check(int fjd){
	int shengA=A-fjd/(len+1)*len-fjd%(len+1),shengB=B-fjd/(len+1);
	return shengA*len>=shengB;
}
signed main(){
	int t=read();
	while(t--){
		A=read(),B=read(),C=read(),D=read();
		len=ceil(max(A,B)*1.0/(min(A,B)+1));
		int lt=0,rt=A+B+1,pos=0;
		while(lt<rt){	
			int mid=(lt+rt)>>1;
			if(check(mid))lt=mid+1;
			else rt=mid;
		}
		pos=lt;
		int shengA=A-pos/(len+1)*len-pos%(len+1),shengB=B-pos/(len+1);
		int fstA=shengB-shengA*len+pos+1;
		for(int i=C;i<=D;i++){
			if(i<=pos){
				if(i%(len+1))putchar('A');
				else putchar('B');
			}
			else if(i>pos&&i<fstA)putchar('B');
			else if(i>=fstA){
				if((i-fstA+1)%(len+1)==1)putchar('A');
				else putchar('B');
			}
		}
		puts("");
	}
	return 0;
}