JSOI2013 快乐的JYY(manacher,回文串)
萌新不会PAM
于是用manacher+hash
O(nlogn)过了这题
首先我们有一个结论
对于一个长度n的串,它的本质不同的回文子串数量是O(n)的
然后我们先用manacher算出半径r[i]
然后开一个数组记录一下最长回文子串在原字符串中哪个位置
我们考虑任意一个>=3的回文子串不论是奇是偶,去掉头尾它依然是回文串
又因为只有O(n)个本质不同的回文子串(以下简称子串),所以我们可以考虑用字符串哈希map给每个本质不同的子串标号,然后每个子串的节点把去掉头尾的子串的节点当作父亲,就类似于AC自动机的fail树,意即你访问子节点的串同时一定遍历了父节点的串,然后只有长度为1或2的子串向根连边(把根当作父亲).
于是这就形成了一颗树
于是我们每遍历一个以某个位置为对称轴(可以是字母也可以是两个字母间的空隙)的最长回文子串就给它打个标记,一个回文子串遍历了多少次显然是它树上的结点的子树和,于是我们可以算出每个回文子串在A中出现了几次,同理对B建树,然后把相同的子串在两树中的方案乘起来再累加到ans里,就做完了
/*快乐的JYY*/ #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cstring> #include<map> using namespace std; #define ll long long const int maxn = 2e5 + 10; #define ul unsigned long long ul mi[maxn]; ll ans = 0; int head[maxn]; int idcnt = 0; struct Edge{ int nxt,point; }edge[maxn*2]; int tot; void add(int x,int y){ edge[++tot].nxt = head[x]; edge[tot].point = y; head[x] = tot; } struct Str{ char str[maxn]; char s[maxn*2]; int r[maxn] ;int bit[maxn];ul hash[maxn];map<ul,int>id; ul v[maxn]; ll dp[maxn * 2]; map<ul,ll>f; int len; int cnt; int rt; #define p 133331 void init(){ for(int i = 1; i <= len; ++i) hash[i] = hash[i-1] * p + str[i] - 'A' + 1; } ul calc(int l,int r){ int k = r - l + 1; return hash[r] - mi[k] * hash[l-1]; } void manacher(){ s[++cnt] = '~',s[++cnt] = '#'; for(int i = 1; i <= len; ++i){ s[++cnt] = str[i]; s[++cnt] = '#'; bit[cnt] = i; } s[++cnt] = '!'; s[cnt+1] = '\0'; int mr = 0,mid = 0; for(int i = 2; i <= cnt - 1; ++i){ if(i <= mr) r[i] = min(r[(mid<<1)-i],mr - i + 1); else r[i] = 1; while(s[i+r[i]] == s[i-r[i]]) r[i]++; if(i + r[i] > mr){ mr = i + r[i] - 1; mid = i; } } } void build(){ rt = ++idcnt; for(int i = 2; i <= cnt - 1; ++i){ int L = i - r[i] + 1,R = i + r[i] - 1; if(L == R && s[L] == '#') continue; L = bit[L] + 1,R = bit[R]; int lst = 0; while(L <= R){ ul val = calc(L,R); if(id.find(val) == id.end()){ id[val] = ++idcnt; v[idcnt] = val; if(lst) add(id[val],lst); } else{ if(lst) add(id[val],lst); break; } lst = id[val]; if(L == R){ add(rt,id[val]); } if(R == L + 1){ add(rt,id[val]); } L++,R--; } L = i - r[i] + 1,R = i + r[i] - 1; L = bit[L] + 1,R = bit[R]; ul val = calc(L,R); dp[id[val]]++; } } void dfs(int x){ for(int i = head[x]; i ; i = edge[i].nxt){ int y = edge[i].point; dfs(y); dp[x] += dp[y]; } f[v[x]] += dp[x]; } }A,B; void init(){ mi[0] = 1; for(int i = 1; i <= 1e5; ++i) mi[i] = mi[i-1] * p; scanf("%s",A.str+1); A.len = strlen(A.str + 1); A.init(); A.manacher(); A.build(); A.dfs(A.rt); scanf("%s",B.str+1); B.len = strlen(B.str + 1); B.init(); B.manacher(); B.build(); B.dfs(B.rt); } void solve(int x){ if(x != A.rt){ ans += A.f[A.v[x]] * B.f[A.v[x]]; } for(int i = head[x]; i ; i = edge[i].nxt){ int y = edge[i].point; solve(y); } } int main() { init(); solve(A.rt); printf("%lld\n",ans); return 0; }