Lydsy(大视野2017八月份月赛)D--

Problem D: 字符串大师

Time Limit: 1 Sec   Memory Limit: 256 MB
Submit: 164   Solved: 47
[ Submit][ Status][ Discuss]

Description

一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节
。给定一个长度为n的仅由小写字符构成的字符串S,请对于每个k(1<=k<=n),求出S长度为k的前缀的最短循环节的
长度per_i。字符串大师小Q觉得这个问题过于简单,于是花了一分钟将其AC了,他想检验你是否也是字符串大师。
小Q告诉你n以及per_1,per_2,...,per_n,请找到一个长度为n的小写字符串S,使得S能对应上per。

Input

第一行包含一个正整数n(1<=n<=100000),表示字符串的长度。
第二行包含n个正整数per_1,per_2,...per_n(1<=per_i<=i),表示每个前缀的最短循环节长度。
输入数据保证至少存在一组可行解。

Output

输出一行一个长度为n的小写字符串S,即某个满足条件的S。
若有多个可行的S,输出字典序最小的那一个。

Sample Input

5
1 2 2 2 5

Sample Output

ababb



思路:根据next数组有求最短循环节的性质,可以由i-a[i](a[i]为输入的数据)得出
next数组,接下来根据 next数组对原字符串进行KMP反演,我们知道next数组的求法是
通过递推得到,如何递推呢,看下面;
  next[i]表示当前以下标i结尾的字符串,最长公共前后缀的长度为next[i],那么
假如next[i]=k已知 我们就相当于知道了
{p[0],p[1]...p[k-1]}={p[i-k+1],p[i-k+2],...p[i]},如果再有p[k]=p[i+1],那么
就有 next[i+1]=next[i]+1=k+1;所以根据next数组不为0的值知道它跟a[i]位置的那个
字母相等,如果next数组值为0, 也就说明 p[i+1]!=p[k],这个k是谁呢,就是
next[i]+1的位置,这时候我们再去寻找更短的k,即去找 next[next[i]+1 ]+1这个位置,
直到k=0;我们把这些位置的字母储存起来 i+1不能与任何一个相同,否则它的next值就
不可能为0,贪心找出不同的最小字母填进去就OK了。

#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
int a[maxn];
int next_[maxn];
char str[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        next_[i]=i-a[i];
    }
    str[1]='a';
    next_[0]=-1;
    for(int i=2;i<=n;i++){
        if(next_[i]!=0)
            {
                str[i]=str[next_[i]];
            }
        else
            {
                set<char>s;
                int k=next_[i-1]+1;
                while(k)
                {
                    s.insert(str[k]);
                    k=next_[k-1]+1;
                }
               char x='a';
                while(!s.empty()){
                    if(x!=*s.begin()) break;
                        else{
                        x++;
                        s.erase(s.begin());
                        }
                }
                str[i]=x;
            }
    }
    printf("%s\n",str+1);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值