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