bzoj4974: [Lydsy八月月赛]字符串大师

传送门

题目可转换为已知一个串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;
}
View Code

 

posted @ 2018-01-03 20:57  啊宸  阅读(172)  评论(0编辑  收藏  举报