【题解】P3279 [SCOI2013]密码

发布时间 2023-04-18 21:50:42作者: flywatre

[SCOI2013]密码

Fish是一条生活在海里的鱼。有一天他很无聊,就到处去寻宝。他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进。

通过翻阅古籍,Fish 得知了这个密码的相关信息:

  1. 该密码的长度为N。

  2. 密码仅含小写字母。

  3. 以每一个字符为中心的最长回文串长度。

  4. 以每两个相邻字符的间隙为中心的最长回文串长度。

很快Fish 发现可能有无数种满足条件的密码。经过分析,他觉得这些密码中字典序最小的一个最有可能是答案,你能帮他找到这个密码么?

注意:对于两个串A和B,如果它们的前i个字符都相同,而A的第i+1个字符比B的第i+1个字符小,那么认为是则称密码A 的字典序小于密码B 的字典序,例如字符串abc 字典序小于字符串acb。如果密码A的字典序比其他所有满足条件的密码的字典序都小,则密码A是这些密码中字典序最小的一个。

输入格式

输入由三行组成。第一行仅含一个整数N,表示密码的长度。第二行包含N 个整数,表示以每个字符为中心的最长回文串长度。第三行包含N - 1 个整数,表示每两个相邻字符的间隙为中心的最长回文串长度。

输出格式

输出仅一行。输出满足条件的最小字典序密码。古籍中的信息是一定正确的,故一定存在满足条件的密码。

题解

先考虑暴力,暴力枚举每个回文串,把所有相同的位置用并查集维护,一定不同的位置用链表存起来。
然后考虑哪些信息是不必要的,模拟manacher的匹配过程,匹配到的点一定包含了所有的信息。

#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=200010;
int n,fa[N],f[N];
int own[N];
char s[N];
int getfa(int x){return (fa[x]==x)?x:fa[x]=getfa(fa[x]);}
vector<int>par[N];
inline void merge(int x,int y){
	x=getfa(x),y=getfa(y);
	if(x!=y)fa[x]=y;
	return ;
}
signed main(){
	n=rd();
	for(int i=1;i<=n*2;i++)fa[i]=i;
	for(int i=1;i<=n;i++)f[i*2-1]=rd();
	for(int i=1;i<n;i++)f[i*2]=rd();
//	for(int i=1;i<=n*2-1;i++)cout<<f[i]<<" ";
//	cout<<"\n";
	for(int i=1,mid=0,r=0;i<=n*2-1;i++){
		int p=1;
		if(i<=r)p=min(f[mid*2-i],r-i+1);
		while(p<f[i])p++,merge(i+p-1,i-p+1);//,cout<<i<<":"<<i-p+1<<"-"<<i+p-1<<":"<<p<<"\n";
		if(i+f[i]-1>r)r=i+f[i]-1,mid=i;
		if(i+f[i]+1<=n*2-1&&i-f[i]-1>=1)par[i+f[i]+1].push_back(i-f[i]-1),par[i-f[i]-1].push_back(i+f[i]+1);
		if(i+f[i]<=n*2-1&&i-f[i]>=1)par[i+f[i]].push_back(i-f[i]),par[i-f[i]].push_back(i+f[i]);
	}
	for(int i=1;i<=n*2-1;i++){
		int x=getfa(i);
		if(x==i)continue;
		for(int j:par[i])par[x].push_back(j);
		vector<int>().swap(par[i]); 
	}
	for(int i=1;i<=n;i++){
		int u=i*2-1,x=getfa(u);
		if(s[x])continue;
		for(int j=0;j<26;j++)own[j]=false;
		for(int j:par[x])if(s[getfa(j)])own[s[getfa(j)]-'a']=1;
		for(int j=0;j<26&&!s[x];j++)if(!own[j])s[x]=j+'a';
	}
	for(int i=1;i<=n;i++)putchar(s[getfa(i*2-1)]);
	return 0;
}