CF1110H Modest Substrings

Modest Substrings

You are given two integers \(L\) and \(R\) . Let's call an integer \(x\) modest, if \(L \le x \le R\) .

Find a string of length \(n\) , consisting of digits, which has the largest possible number of substrings, which make a modest integer. Substring having leading zeros are not counted. If there are many answers, find lexicographically smallest one.

If some number occurs multiple times as a substring, then in the counting of the number of modest substrings it is counted multiple times as well.

\(1\leq L\leq R\leq 10^{800},n\leq 2000\)

题解

先只考虑\(\leq R\)的限制。回忆描述一个数\(\leq R\)需要满足的条件:

  • \(|x|< |R|\)

    只要这些长度\(< |R|\)的子串开头不是\(0\)就要统计进答案。

    这个比较好做,直接在每个位置统计以它开头的子串的答案就行了。

  • \(|x|=|R|\)\(x\)\(R\)的LCP的下一位满足\(x[i]< R[i]\)

    注意到这里需要知道\(x\)\(R\)的LCP,所以考虑AC自动机。

    我们只在这些串和\(R\)的LCP后第一个小于\(R\)的位置统计答案。那么只要在当前匹配到的节点选择的下一条出边小于\(R[i]\),并且我们要构造的串的剩余长度不小于某个下限,就要统计进答案。

    每个AC自动机节点还要对fail树上的祖先特殊处理一下。

  • \(x=R\)

    这些串直接在向AC自动机终止节点转移的边上统计答案就行了。

回到原题要求\(L\leq x\leq R\)。我们直接用统计\(\leq R\)的减去统计\(\leq L-1\)的就行了。

时间复杂度\(O(n(|L|+|R|)\Sigma)\)

CO int N=2e3+10;
char L[N],R[N];
int tot;
int ch[N][10],fa[N],val[N][10][N];

void insert(char str[],int n){
	int x=0;
	for(int i=1;i<=n;++i){
		int c=str[i]-'0';
		if(!ch[x][c]) ch[x][c]=++tot;
		x=ch[x][c];
	}
}
void build(char str[],int n,int v){
	int x=0;
	for(int i=1;i<=n;++i){
		int c=str[i]-'0';
		for(int d=x==0;d<c;++d) val[x][d][n-i+1]+=v; // edit 1: x=0 -> d starts from 1
		if(i==n) val[x][c][1]+=v;
		x=ch[x][c];
	}
}


int F[N][N];

int main(){
	scanf("%s",L+1);
	int lenL=strlen(L+1);
	if(L[lenL]>'0') --L[lenL];
	else{
		int p=lenL;
		while(p>1 and L[p]=='0') --p;
		--L[p],fill(L+p+1,L+lenL+1,'9');
	}
	if(L[1]=='0' and lenL>1)
		copy(L+2,L+lenL+1,L+1),L[lenL--]=0;
	if(L[1]>'0') insert(L,lenL); // edit 2: L=0 -> don't care about it
	
	scanf("%s",R+1);
	int lenR=strlen(R+1);
	insert(R,lenR);
	
	deque<int> que;
	for(int c=0;c<=9;++c)if(ch[0][c]) que.push_back(ch[0][c]);
	while(que.size()){
		int x=que.front();que.pop_front();
		for(int c=0;c<=9;++c){
			if(!ch[x][c]) {ch[x][c]=ch[fa[x]][c]; continue;}
			fa[ch[x][c]]=ch[fa[x]][c],que.push_back(ch[x][c]);
		}
	}
	
	if(L[1]>'0') build(L,lenL,-1);
	build(R,lenR,1);
	
	int n=read<int>();
	for(int x=1;x<=tot;++x)for(int c=0;c<=9;++c) // edit 3: x starts from 1
		for(int i=1;i<=n;++i) val[x][c][i]+=val[fa[x]][c][i];
	
	for(int x=0;x<=tot;++x)for(int c=1;c<=9;++c) // edit 4: c starts from 1
		for(int i=1;i<lenL;++i) val[x][c][i]+=-1;
	for(int x=0;x<=tot;++x)for(int c=1;c<=9;++c)
		for(int i=1;i<lenR;++i) val[x][c][i]+=1;
	
	for(int x=0;x<=tot;++x)for(int c=0;c<=9;++c)
		for(int i=1;i<=n;++i) val[x][c][i]+=val[x][c][i-1];
	
//	for(int x=0;x<=tot;++x)for(int c=0;c<9;++c)
//		for(int i=1;i<=n;++i) cerr<<x<<" "<<c<<" "<<i<<" v="<<val[x][c][i]<<endl;
	
	for(int i=n-1;i>=0;--i)for(int x=0;x<=tot;++x){
		F[i][x]=-1e9; // edit 5: initialize F=-inf
		for(int c=0;c<=9;++c) F[i][x]=max(F[i][x],F[i+1][ch[x][c]]+val[x][c][n-i]);
	}
	printf("%d\n",F[0][0]);
	for(int i=0,x=0;i<n;++i){
		int c=-1;
		for(int d=0;d<=9;++d)
			if(F[i][x]==F[i+1][ch[x][d]]+val[x][d][n-i]) {c=d; break;}
		printf("%d",c);
		x=ch[x][c];
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12730933.html