正题
题目链接:https://www.luogu.org/problemnew/show/P3279
题目大意
一个字符串满足:
- 有nnn个字符
- 仅包含小写字母
- 告诉你每个字符为中心的最大回文串长度
- 告诉你每个两个字符的间隙为中心的最大回文串长度
求满足要求的字典序最小的字符串。
解题思路
因为字典序最小,所以优先满足前面的最小。我们可以找出相同不相同的关系。然后对于每段相等关系就将前面的一半复制到后面去
这样是O(n2)O(n^2)O(n2)的,并不能胜任此题,我们可以发现很多关系都是重复的,所以需要使用ManacherManacherManacher逆推找出O(n)O(n)O(n)的关系。
我们先将字符串的间隙之间插入′∗′'*'′∗′字符然后现在我们这知道每个串为中心的回文串,用fi,jf_{i,j}fi,j表示第iii个位置不可以填jjj这个字符,rir_iri表示以iii为中心的最长回文串长度。
一个位置会被更新多次,我们考虑两种情况
- 若i≤maxrighti\leq maxrighti≤maxright那么我们知道目前的iii中是min{maxright−i+1,r2∗pos−i}min\{maxright-i+1,r_{2*pos-i}\}min{maxright−i+1,r2∗pos−i}的字符是已经更新过的,无需再更新
- 若i>maxrighti>maxrighti>maxright那么我们无法知道iii的已更新回文串的信息,那么就老老实实的全部更新
然后要注意中间的不相等情况也需要O(1)O(1)O(1)更新
然后更新maxrightmaxrightmaxright
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+100;
int n,r[N],maxn,pos;
bool f[N][26];
char str[N];
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&r[i*2-1]),r[i*2-1]++;for(int i=1;i<n;i++)scanf("%d",&r[i*2]),r[i*2]++;n=n*2;str[0]='*';str[1]='a';r[0]=1;for(int i=0,mr=-1;i<=n;i++){int j=0;if(!(i&1)) str[i]='*';else if(str[i]<'a'){for(;j<26;j++)if(!f[i][j]) break;str[i]=j+'a';}if(maxn>i) j=min(maxn-i+1,r[2*pos-i]);else j=1;for(j--;j<r[i];j++) str[i+j]=str[i-j];if(r[i]<=i) f[i+r[i]][str[i-r[i]]-'a']=1;if(maxn<i-j+1) maxn=i+r[i]-1,pos=i;}for(int i=1;i<=n;i+=2)printf("%c",str[i]);
}