题目可转换为已知一个串kmp之后的nxt数组,求字典序最小的原串。
已知第i位结尾的串循环节长度位x,那么nxt[i]=i-x;
当nxt不为0时,s[i]=s[nxt[i]];
nxt为0时,那么考虑kmp的过程,沿着nxt[i-1]一直往前跑找到的每一个j,s[j+1]都不能是现在的s[i],那么在一路求nxt的过程中就从前往后递推用一个二进制串表示一路的nxt的后一位出现过的字母,然后每次取未出现过的字典序最小的字母即可;
//Achen #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<vector> #include<queue> #include<cmath> #include<ctime> const int N=100007; typedef long long LL; using namespace std; int n,nxt[N],vis[N]; char s[N]; template<typename T> void read(T &x) { T f=1; x=0; char ch=getchar(); while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar(); if(ch==‘-‘) f=-1,ch=getchar(); for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘; x*=f; } int main() { #ifdef DEBUG freopen("1.in","r",stdin); freopen("1.out","w",stdout); #endif read(n); for(int i=1;i<=n;i++) { read(nxt[i]); nxt[i]=i-nxt[i]; } s[0]=‘a‘; vis[1]=1; for(int i=2;i<=n;i++) { if(nxt[i]!=0) s[i-1]=s[nxt[i]-1]; else { for(int j=0;j<26;j++) if(!(vis[i-1]&(1<<j))) { s[i-1]=‘a‘+j; break; } } vis[i]=(vis[nxt[i]]|(1<<(s[nxt[i]]-‘a‘))); } puts(s); return 0; }
原文地址:https://www.cnblogs.com/Achenchen/p/8185648.html
时间: 2024-11-05 19:45:07