agc020_d Min Max Repetition

agc020_d Min Max Reptition

https://atcoder.jp/contests/agc020/tasks/agc020_d

定义 \(f(A,B)\) 为参数为两个正整数 \(A,B\) ,结果为一个字符串的函数.

\(f(A,B)\) 满足以下要求

  1. 长度为 \(A+B\)
  2. \(A\) 个'A'和 \(B\) 个'B'
  3. 在满足1,2的条件下,最小化连续的'A'或'B'的长度
  4. 在满足1,2,3的条件下,最小化字典序

\(Q\) 组询问,每组询问给出 \(A,B,C,D\) ,求 \(f(A,B)[C \cdots D]\)

\(1 \le Q \le 10^3\)

\(1 \le A_i,B_i \le 5 \times 10^8\)

\(1 \le C_i \le D_i \le A_i+B_i\)

\(D_i-C_i+1 \le 100\)

Tutorial

\(K\)\(f(A,B)\) 中最长相同字符连续段的长度.考虑求出 \(K\)

不妨设 \(A<B\) ,根据抽屉原理,将 \(B\) 个字符放入 \(A+1\) 个抽屉中.所以得到

\[K=\lceil \dfrac {B}{A+1} \rceil \]

也就是说,有

\[K = \lceil \dfrac {\max\{A_i,B_i\}}{\min\{A_i,B_i\}+1} \rceil \]

我们考虑贪心构造,即依次填入每个字符,满足

  1. 当前连续字符长度小于等于 \(K\)
  2. 存在填补后面的字符串的合法方案

发现在一段前缀中,第2个条件是没有限制的.所以这段前缀形如"AA...ABA...ABAA..."其中除了最后一段外其他部分的'A'的连续段的长度为 \(K\) .

对于剩下的部分,设还有 \(A'\) 个'A'和 \(B'\) 个'B',此时一定有 \(B' \le K(A'+1)\) .

那么我们可以贪心的先放置一段连续的'B',使得 \(B'=KA'\) ,之后的部分形如"ABB...BABB...B..."其中'B'的连续段长度均为 \(K\)

那么我们只需要知道第一部分的长度,就可以很容易得到整个串的形态, \(O(1)\) 的得知每个位置的字符了.

考虑二分第一部分的'A'的数量 \(Na\) ,则 \(Nb=\lfloor \dfrac {Na-1}K \rfloor\) ,那么就可以得到 \(A',B'\) 判断.

时间复杂度 \(O(Q(\log A+D_i-C_i+1)\)

Code

#include <algorithm>
#include <cstdio>
#include <iostream>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
inline char nc()
{
//	return getchar();
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void read(T &x)
{
	x=0; int f=1,ch=nc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
	x*=f; 
}
typedef long long ll;
int A;
int B;
int C;
int D;
int K;
int Q;
bool check(int Na)
{
	int Nb=Na==0?0:(Na-1)/K;
	return (B-Nb)<=(ll)(A-Na+1)*K;
}
int main()
{
	read(Q);
	for(int kase=1;kase<=Q;++kase)
	{
		read(A),read(B),read(C),read(D);
		K=(max(A,B)-1)/(min(A,B)+1)+1;
		int l=0,r=A,Na=-1;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(check(mid)) Na=mid,l=mid+1;
			else r=mid-1;
		}
		int Nb=Na==0?0:(Na-1)/K;
		int t=(B-Nb)-(A-Na)*K;
		for(int i=C;i<=D;++i)
		{
			int x=i;
			if(x<=Na+Nb) putchar(x%(K+1)==0?'B':'A');
			else
			{
				x-=Na+Nb;
				if(x<=t) putchar('B');
				else
				{
					x-=t;
					putchar(x%(K+1)==1?'A':'B');
				}
			}
		}
		putchar('\n');
	}
	return 0;
}
posted @ 2020-05-30 12:22  LJZ_C  阅读(111)  评论(0编辑  收藏  举报