文章目录
- 题目描述
- 解析
- 1.p[i]>0:
- 2.p[i]=0:
- 代码
题目描述
解析
我个人做起来很费劲的一道题,用vector,并查集等等东西搞来搞去过掉了(竟然只WA了一次 )
看题解思路就一下子清晰了,还是对KMP的理解不到位。
现在看看题解的表演吧
首先容易想到,若设kmp的失配数组为p,则有:p[i]=i−pre[i]p[i]=i-pre[i]p[i]=i−pre[i]
现在问题就是如何利用失配数组逆推出字符串
因为字典序贪心显然是正确的
所以我们可以从前往后推导
假设[1,i-1]的字符串都已求出,如何求出符合要求且字典序最小的第i位
回忆一下kmp匹配的流程:
void kmp(){p[1]=0;for(int i=1,j=0;i<=l;i++){while(j>0&&s[i+1]!=s[j+1]) j=p[j];if(s[i+1]==s[j+1]) j++;p[i+1]=j;}return;
}
可以分为两种情况
1.p[i]>0:
此时通过上面的流程,可以发现:
s[i]=s[p[i]]s[i]=s[p[i]]s[i]=s[p[i]]
就很容易了
2.p[i]=0:
我们首先要明白p[i]=0是怎么得到的
因为kmp计算里的那个while语句始终成立,也就是s[i+1]!=s[j+1],导致j一直跳失配跳到了0
所以当前这一位只要和往前跳的那些不同就可以了
注意如果这个i不是第一位的话,它也应该是与第1位不同的
分析完上面两种情况后,问题就变得很简单啦
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef unsigned long long ull;
const int N = 1e6+100;
const int M=1e7+5;
const int mod=1e9+7;
int n,m;
int l;
int p[N];
char s[N];int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&m);p[i]=i-m;if(p[i]>0){s[i]=s[p[i]];}else{bool jd[28]={};int pl=p[i-1];while(pl){jd[s[pl+1]-'a'+1]=1;pl=p[pl];}if(i!=1) jd[1]=1;for(int j=1;j<=26;j++){if(!jd[j]){s[i]='a'+j-1;break;}}}}printf("%s",s+1);return 0;
}