BZOJ4974 大视野1708月赛 字符串大师

传送门

题目大意

给定一个字符串的每一个前缀的最短循环节长度,求符合要求的字典序最小的字符串。

 

题解

给定循环节最短长度就是给定了这个字符串$kmp$的$next$数组,即$X_i=i-next_i$,$X_i$表示给定的循环节长度。

由于答案一定有解,考虑模拟构造一个这样的字符串,并模拟求它的$next$数组的过程。如果匹配到发现$i$从$j$处转移,那么就用$j$处的字母赋给$i$,否则就得到了$i,j$互不相同的条件,我们就得到了一个$i$不能取得字符集$S$,对$S$取$mex$即可。

 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 100020
using namespace std;
namespace IO{
	const int BS=(1<<20); int Top=0;
	char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
	void flush(){fwrite(OT,1,OS-OT,stdout);}
	void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
	void write(int x){
		if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
		while(x) SS[++Top]=x%10,x/=10;
		while(Top) Putchar(SS[Top]+'0'),--Top;
	}
	int read(){
		int nm=0,fh=1; char cw=Getchar();
		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
		return nm*fh;
	}
}
using namespace IO;
int n,m,p[M],nxt[M]; char s[M]; bool G[M][26];
int main(){
	n=read(),s[1]='a',nxt[0]=-1,memset(G,true,sizeof(G));
	for(int i=1;i<=n;i++) p[i]=read(),nxt[i]=i-p[i]; Putchar('a');
	for(int i=2;i<=n;i++){
		for(int j=nxt[i-1]+1;j>=0;j=nxt[j-1]+1){
			if(!j){for(int k=0;k<26;k++) if(G[i][k]){s[i]=k+'a';break;}}
			else if(nxt[i]==j) s[i]=s[j];
			else{G[i][s[j]-'a']=false;continue;}break;
		} Putchar(s[i]);
	}Putchar('\n'),flush(); return 0;
}

 

posted @ 2018-10-21 14:29  OYJason  阅读(169)  评论(0编辑  收藏  举报