AGC029C - Lexicographic constraints 题解

原题链接:C - Lexicographic constraints
题目大意:有\(N\)个字符串,已知它们是从小到大排列的(按照字典序),现在仅知道每个字符串的长度,问这些字符串的字符集最小是多少。


题解:上来直接考虑贪心,似乎不大行,然后想DP,乱七八糟后效性一大堆,于是开始考虑二分答案。

首先特判掉1的情况(所有字符串长度严格递增),然后考虑二分答案\(x\),贪心思路很好想,就是在\(x\)进制下摆数,看能不能摆下。

字符串长度\(\leq 10^9\),看上去要爆,但是,实际上的非零位置不会超过\(n\)个,只需要对这些非零位处理即可,时间复杂度\(O(n\log n)\)

代码:

#include <cstdio>
void read(int &a){
	a=0;
	char c=getchar();
	while(c<'0'||c>'9'){
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		a=(a<<1)+(a<<3)+(c^48);
		c=getchar();
	}
}
const int Maxn=200000;
int a[Maxn+5];
int n;
int pos[Maxn+5],num[Maxn+5],len;
bool check(int x){
	len=0;
	num[0]=0;
	for(int i=1;i<=n;i++){
		if(a[i]>a[i-1]){
			continue;
		}
		if(len==0){
			pos[++len]=a[i];
			num[len]=1;
			continue;
		}
		while(len>0&&pos[len]>a[i]){
			len--;
		}
		if(len>0&&pos[len]==a[i]){
			num[len]++;
			while(len>0&&num[len]==x){
				int now=pos[len]-1;
				len--;
				if(pos[len]==now){
					num[len]++;
				}
				else{
					pos[++len]=now;
					num[len]=1;
				}
			}
		}
		else{
			pos[++len]=a[i];
			num[len]=1;
		}
		if(num[0]>0){
			return 0;
		}
	}
	return 1;
}
int main(){
	read(n);
	bool one=1;
	for(int i=1;i<=n;i++){
		read(a[i]);
		if(a[i]<=a[i-1]){
			one=0;
		}
	}
	if(one){
		puts("1");
		return 0;
	}
	int left=2,right=n,mid;
	while(left<right){
		mid=(left+right)>>1;
		if(check(mid)){
			right=mid;
		}
		else{
			left=mid+1;
		}
	}
	printf("%d\n",left);
	return 0;
}
posted @ 2020-02-28 23:16  with_hope  阅读(193)  评论(0)    收藏  举报