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
#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;
}