题目描述:
Fish是一条生活在海里的鱼。有一天他很无聊,就到处去寻宝。他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进。
通过翻阅古籍,Fish 得知了这个密码的相关信息:
-
该密码的长度为N。
-
密码仅含小写字母。
-
以每一个字符为中心的最长回文串长度。
-
以每两个相邻字符的间隙为中心的最长回文串长度。
很快Fish 发现可能有无数种满足条件的密码。经过分析,他觉得这些密码中字典序最小的一个最有可能是答案,你能帮他找到这个密码么?
注意:对于两个串A和B,如果它们的前i个字符都相同,而A的第i+1个字符比B的第i+1个字符小,那么认为是则称密码A 的字典序小于密码B 的字典序,例如字符串abc 字典序小于字符串acb。如果密码A的字典序比其他所有满足条件的密码的字典序都小,则密码A是这些密码中字典序最小的一个。
题解:
manacher反演?
贪心+并查集,判断这一位上字符的时候只需要与前边的1个点制造联系。
和manacher好像啊。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,p[2*N]; int hed[2*N],cnt; struct EG { int to,nxt; }e[4*N]; void ae(int f,int t) { e[++cnt].to = t; e[cnt].nxt = hed[f]; hed[f] = cnt; } int col[2*N],fa[2*N]; bool vis[28]; int findfa(int x) { if(x==fa[x])return x; return fa[x]=findfa(fa[x]); } int main() { n=rd(); for(int i=2;i<=2*n;i+=2) p[i]=rd(); for(int i=3;i<=2*n-1;i+=2) p[i]=rd(); for(int i=2;i<=2*n;i++) fa[i]=i; int mx = 0; for(int i=2;i<=2*n;i++) { for(int j=max(i&1,mx-i+(i&1));j<=p[i];j+=2) { int f1 = findfa(i-j),f2 = findfa(i+j); if(f1!=f2)fa[f2]=f1; } mx = max(mx,i+p[i]-(i&1)); } for(int i=2;i<=2*n;i++) { int f1 = findfa(i-p[i]-1); int f2 = findfa(i+p[i]+1); ae(f2,f1);ae(f1,f2); } mx=0; for(int i=2;i<=2*n;i+=2) { int ff = findfa(i); if(!col[ff]) { for(int j=1;j<=26;j++)vis[j]=0; for(int j=hed[ff];j;j=e[j].nxt) vis[col[e[j].to]]=1; for(int j=1;j<=26&&!col[ff];j++) if(!vis[j])col[ff]=j; } printf("%c",col[ff]+'a'-1); if(i+p[i]-1>mx) { for(int j=mx+2;j<=i+p[i]-1;j+=2) col[j]=col[i*2-j]; mx=i+p[i]-1; } } printf("\n"); return 0; }