- 题目大意
- 输入格式
- 输出格式
- 样例
- 样例输入
- 样例输出
- 样例说明
- 题解
- 代码很丑
题目大意
给定一个包含26个小写字母的字符串,字符从0开始标号。一个子串a的价值定义为:a在S中的所有出现位置中点的异或值。(规定:若a出现在s[l……r],那么a的中点为 l+r2(向下取整) ).求:对于所有 回文子串 a,最大的价值是多少?
输入格式
第一行,一个整数num,( 1≤num≤5 ),表示数据组数;
每组数据占一行,有一个仅含小写字母的字符串S.
输出格式
对于每组数据,输出一行,表示最大价值.
样例
样例输入
1
aabacabaaa
样例输出
15
样例说明
对于回文子串aa,所有出现位置的中点为:0,7,8;
0^7^8=15
题解
回文自动机记的是右端点,似乎不太好用,关键是我不会写回文树。
所以还是考虑一下manacher+hash.
先用manacher跑一遍字符串,可以看出,只有在暴力扩展右边界时会产生新的本质不同的回文串.
这些本质不同的回文串的数目是O(n)的。
我们需要把中间部分相同的串连接起来形成一棵树.
比如:abbba是bbb的子节点,bbb是b的子节点.子串用hash值映射到节点.
本来用的是map,发现超时很严重,于是看了下网上各位大佬的代码,发现大佬们用的是hash_table.
居然用黑科技!我等蒟蒻还是用链表hash算了。
代码(很丑)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define MAXN 1005000
#define LL long long
#define ULL unsigned long long
const ULL s1=131,s2=129;
const ULL m1=19980403,m2=998244353;
char s[MAXN],t[MAXN*2];
ULL h1[MAXN],h2[MAXN],pow1[MAXN],pow2[MAXN];
int Next[MAXN<<2],End[MAXN<<2],Last[m1+10],Len[MAXN<<2],e=0;
void add(ULL x,int p)
{ULL a,b;a=x>>32;b=x-(a<<32);End[++e]=b;Len[e]=p;Next[e]=Last[a];Last[a]=e;return ;
}
int find(ULL x)
{ULL a,b;a=x>>32;b=x-(a<<32);for(int t=Last[a];t;t=Next[t]){if(End[t]==b){return Len[t];}}return -1;
}
int L,len;
map<ULL,int>T;
void init()
{ pow1[0]=pow2[0]=1; h1[0]=h2[0]=0; for(int i=1;i<=L;i++) { pow1[i]=pow1[i-1]*s1%m1; pow2[i]=pow2[i-1]*s2%m2; h1[i]=(h1[i-1]*s1+s[i])%m1; h2[i]=(h2[i-1]*s2+s[i])%m2; } return ;
}
ULL cal(int l,int r)
{ ULL t1,t2; t1=(h1[r]+m1-h1[l-1]*pow1[r-l+1]%m1)%m1; t2=(h2[r]+m2-h2[l-1]*pow2[r-l+1]%m2)%m2; return (t1<<32)|t2;
}
int fa[MAXN],dp[MAXN],p[MAXN*2],tot=0,ans=0;
void work()
{ memset(p,0,sizeof(p));memset(s,0,sizeof(s));memset(Last,0,sizeof(Last));e=0;//T.clear(); tot=0; scanf("%s",s+1); L=strlen(s+1); init(); t[0]='$'; len=0; for(int i=1;i<=L;i++) { t[++len]='#'; t[++len]=s[i]; } t[++len]='#'; t[++len]='@'; int mx=0,id=0,lst; ULL tt;for(int i=1;i<len;i++) { p[i]=mx>i?(min(mx-i,p[(id<<1)-i])):1; //lst=(p[i]==1)?0:T[cal(((i-p[i])>>1)+1,(i+p[i]-1)>>1)];lst=(p[i]==1)?0:find(cal(((i-p[i])>>1)+1,(i+p[i]-1)>>1)); for(;t[i-p[i]]==t[i+p[i]];) { ++p[i]; tt=cal(((i-p[i])>>1)+1,(i+p[i]-1)>>1);if(find(tt)<0) { //T[tt]=++tot;++tot;add(tt,tot); dp[tot]=0;fa[tot]=lst; lst=tot; } else { //lst=T[tt]; lst=find(tt);} } if(lst) { dp[lst]^=(i>>1)-1; } if(i+p[i]>mx) { mx=i+p[i]; id=i; } } ans=0; for(int i=tot;i>=1;i--) { ans=max(ans,dp[i]); dp[fa[i]]^=dp[i]; } printf("%d\n",ans); return ;
}
int main()
{ int Tt; scanf("%d",&Tt); while(Tt) { work(); --Tt; } return 0;
}
上面这段丑代码,显然是用了map发现T了,然后改成链表的。链表部分的变量名沿用了链式存图的变量名.