AT4502 [AGC029C] Lexicographic constraints

题目链接

题意分析

由于这道题的话 答案是单调的 所以我们用二分答案求解

对于相邻的两个串\(S_i\)以及\(S_{i+1}\)

如果\(|S_i|\)<\(|S_{i+1}|\) 那么\(S_{i+1}\)就是\(S_i\)后接a

如果\(|S_i|\)>\(|S_{i+1}|\) 我们考虑先删除\(S_i\)\(|S_i|-|S_{i+1}|\)那一部分 然后把剩下的部分看作一个\(k+1\)进制数 进行+1即可

当然 如果最后连第一位都进位的话 当前答案显然是不成立的

由于直接暴力操作太难了 我们考虑用一个单调栈维护 维护所有位置上已经不是1的位置信息

具体分析见代码

CODE:

#include<bits/stdc++.h>
#define N 200080
#define INF 2100000000
using namespace std;
int n,ans,top;
int num[N];
struct Node
{
	int nowat,nowhave;
}sta[N];
void insert(int len,int now)
{
	while(top>0&&sta[top].nowat>len) --top;
	if(sta[top].nowat==len) sta[top].nowhave++;//如果刚好对应上的话 这一位就+1(比如说b->c)
	else sta[++top]=(Node){len,1};否则的话 也是+1 不过是a->b
	if(sta[top].nowhave==now) --top,insert(len-1,now);//当前进位 删去 然后位置向前提一位
} 
bool check(int now)
{
	sta[top=1]=(Node){0,0};//边界条件
	for(int i=2;i<=n;++i)
	if(num[i]<=num[i-1]) insert(num[i],now);
	return sta[1].nowhave==0;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&num[i]);
	int st=0;
	for(int i=2;i<=n;++i) st+=num[i]>num[i-1];
	if(st==n-1) {printf("1\n");return 0;}//现特判一下只用一个字符就可以的情况
	int le=2,ri=n;
	while(le<=ri)
	{
		int mid=(le+ri)>>1;
		if(check(mid)) ans=mid,ri=mid-1;
		else le=mid+1;
	}
	printf("%d\n",ans);
	return 0;
} 
原文地址:https://www.cnblogs.com/tcswuzb/p/14425298.html