• 【bzoj4974】字符串大师 逆模拟KMP


    题目描述

    一个串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。

    输入

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

    输出

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

    样例输入

    5
    1 2 2 2 5

    样例输出

    ababb


    题解

    逆模拟KMP

    首先有个易证的常用结论:1~n的最短循环节长度等于n-next[n],其中next为KMP算法中的next数组。

    那么我们可以从前往后扫一遍。

    当next不等于0时,由于next的定义为最长公共前后缀的长度,因此可以直接在前面的部分找到(s[next[i]])。由于题目保证有解,因此无需验证其正确性。

    当next等于0时,考虑KMP算法求next的过程:对于上一个匹配位置,如果其下一个字符不等于当前字符,则当前匹配位置调整到其next的位置。如此循环直到下一个字符等于当前字符或者当前匹配位置为-1。然后next等于当前匹配位置+1。

    由于当前的next等于0,意味着上一个匹配位置的任意的next的下一个字符都不等于当前字符。此时只需要循环向前重复找next的过程,并把下一个位置的字符设为不可选择。由于要求字典序最小,所以当前字符即为可以选择的字符中字典序最小的字母。

    时间复杂度$O(26n)$

    #include <cstdio>
    #include <cstring>
    int next[100010] , vis[26];
    char str[100010];
    int main()
    {
    	int n , i , j;
    	scanf("%d" , &n);
    	next[0] = -1;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%d" , &next[i]) , next[i] = i - next[i];
    		if(next[i]) str[i] = str[next[i]];
    		else
    		{
    			for(j = next[i - 1] ; ~j ; j = next[j]) vis[str[j + 1] - 'a'] = i;
    			for(j = 0 ; j < 26 ; j ++ )
    				if(vis[j] != i)
    					break;
    			str[i] = j + 'a';
    		}
    	}
    	printf("%s
    " , str + 1);
    	return 0;
    }
    

     

  • 相关阅读:
    Mybatis(二)入门程序通过id查找用户、模糊查找用户、添加用户、删除用户
    excel测试数据导入
    (转)接口自动化测试之http请求实践总结
    (转)TestNG框架提供两种传入参数的方法:
    Jmeter 集成Excel读写接口参数返回值
    优化问题
    redux
    clientHeight offsetTop scrollTop
    antddesign
    ACMICPC实验室周赛2020.3.6
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7559669.html
Copyright © 2020-2023  润新知