zoukankan      html  css  js  c++  java
  • 【BZOJ4974】字符串大师(LYDSY1708)-KMP+构造

    测试地址:字符串大师
    做法: 本题需要用到KMP+构造。
    看到这种求字符串循环节之类的东西,就立刻想到KMP。联系这题循环节的定义,我们发现,把条件描述中的前缀改成后缀,答案显然也是一样的。于是我们得出一个大胆的结论:前缀ii的最短循环节长度等于inextii-next_i,其中nextinext_i正是KMP算法中的nextnext数组。
    如果要严格证明的话也不难,令T=inextiT=i-next_i,那么前缀nextinext_i和前缀ii的两个长为TT的后缀是相同的。又因为前缀nextinext_i是前缀ii的后缀,所以前缀nextiTnext_i-T和前缀nextinext_i的两个长为TT的后缀是相同的,以此类推,最后前缀ii剩下一段长度小于TT的部分没有得到匹配,说明TT是前缀ii的循环节。而要使TT最小,显然按照KMP算法来做是最优的。
    因此直接用KMP算法构造,如果nexti>0next_i>0,当前位置上的字符应和nextinext_i位置上的字符相同,否则,先求出用nextnext匹配会走过的路径,在这条路径上的所有字符都不应该和当前字符匹配,所以我们在当前位置上放能放的最小的字符即可。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,nxt[100010],a[100010];
    bool vis[30]={0};
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&nxt[i]);
    		nxt[i]=i-nxt[i];
    	}
    	nxt[0]=0;
    	
    	for(int i=1;i<=n;i++)
    	{
    		memset(vis,0,sizeof(vis));
    		int last=nxt[i-1];
    		while(last&&last+1!=nxt[i])
    			vis[a[last+1]]=1,last=nxt[last];
    		if (last+1==nxt[i]) a[i]=a[nxt[i]];
    		else
    		{
    			if (last+1<i) vis[a[last+1]]=1;
    			for(int j=0;j<26;j++)
    				if (!vis[j]) {a[i]=j;break;}
    		}
    		printf("%c",a[i]+'a');
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    MySQL Backup mysqldump 常用选项与主要用法--转发
    openssl 之RSA加密
    Windows 之Dll/lib导出
    缓存雪崩、击穿、穿透
    时间复杂度
    分布式事务
    mysql主从复制与读写分离
    什么是消息队列?
    微服务架构演化
    高并发问题常规思路
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793252.html
Copyright © 2011-2022 走看看