题意
定义 rev(S) 为串 S 的颠倒,如 rev(abac)=caba
现给出一个串,在他的所有子串中,任意两个串 a,b,不能出现 a=b或a=rev(b) 的情况,求集合的最大值
题解
将原串的本质不同的子串分为3种,第一种是回文串,第二种是满足 s=rev(s) 的,第三种是剩余的,设其数量分别为 x、y、z
将原串颠倒后拼接在其后面,再求一次子串个数,发现,第一种为 x,第二种为 y,第三种为 2⋅z
而我们的目的是想去掉 y 中的一半,发现,在加上一个 x 后,除以 2 就是答案
所以要求原串中本质不同的回文串的个数 x
代码
#include<bits/stdc++.h>
#define N 400010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<<x<<endl
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pp;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
char s[N];
int sa[N],t[N],t2[N],c[N],n,rak[N],height[N];
void build_sa(int m,char *s)
{
int i,*x=t,*y=t2;
for (i=0;i<m;i++)c[i]=0;
for (i=0;i<n;i++)c[x[i]=s[i]]++;
for (i=1;i<m;i++)c[i]+=c[i-1];
for (i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for (int k=1;k<=n;k<<=1)
{
int p=0;
for (i=n-k;i<n;i++)y[p++]=i;
for (i=0;i<n;i++)if (sa[i]>=k)y[p++]=sa[i]-k;
for (i=0;i<m;i++)c[i]=0;
for (i=0;i<n;i++)c[x[y[i]]]++;
for (i=0;i<m;i++)c[i]+=c[i-1];
for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1; x[sa[0]]=0;
for (i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if (p>=n) break;
m=p;
}
}
void getheight()
{
int i,j,k=0;
for (i=0;i<n;i++)rak[sa[i]]=i;
for (i=0;i<n;i++){
if (k)k--;
if (!rak[i])continue;
j=sa[rak[i]-1];
while (s[i+k]==s[j+k])k++;
height[rak[i]]=k;
}
}
gp_hash_table<LL,bool>mp;
int str_t,slen,cnt,r[N];
LL p1[N/2],p2[N/2],h1[N/2],h2[N/2];
pp v[N];
char ss[N];
int Init(char *s){
int len=strlen(s+1);
ss[0]='$';ss[1]='#';
int j=2;
for (int i=1;i<=len;i++)ss[j++]=s[i],ss[j++]='#';
ss[j]='\0';
return j;
}
void Manacher(char *s){
int len=Init(s);
int p,mx=0;
for (int i=1;i<len;i++) {
if (i<mx) r[i]=min(r[2*p-i],mx-i);else r[i]=1;
while (ss[i-r[i]]==ss[i+r[i]]) r[i]++;
if (mx<i+r[i])p=i,mx=i+r[i];
}
str_t=0;
for (int i=2;i<len;i++) {
if (ss[i]=='#' && r[i]==1) continue;
int x=i/2-r[i]/2+1,y=i/2+r[i]/2-!(i&1);
v[str_t++]=pp(x,y);
}
}
inline LL cal(LL *h,LL *hh,int x,int y){
LL t1=(h[y]-h[x-1]*p1[y-x+1]%mod+mod)%mod,
t2=(hh[y]-hh[x-1]*p2[y-x+1]%P+P)%P;
return t1<<30|t2;
}
int goooo(char *s){
Manacher(s);
for (int i=0;i<str_t;i++){
int l=v[i].fi,r=v[i].se;
while(l<=r){
LL tm=cal(h1,h2,l,r);
int t=mp[tm];
if (t) break;
mp[tm]=1;
cnt++;
l++,r--;
}
}
return cnt;
}
int main()
{
p1[0]=p2[0]=1;
for(int i=1;i<N/2;i++) p1[i]=p1[i-1]*1331%mod,p2[i]=p2[i-1]*1331%P;
scanf("%s",s+1);n=strlen(s+1);
for(int i=1;i<=n;i++)
h1[i]=(h1[i-1]*1331+s[i])%mod,h2[i]=(h2[i-1]*1331+s[i])%P;
int ans1=goooo(s);
for(int i=0;i<n;i++) s[i]=s[i+1];s[n]='0';int m=n;
for(int i=1;i<=n;i++) s[m+i]=s[m-i];
n=n*2+2; s[n-1]='$'; s[n]=0;
build_sa(200,s);
getheight();
LL ans2=0;
for(int i=2;i<=n;i++){
int tm,tt;
if (sa[i]>m) tm=n-1-sa[i];else tm=m-sa[i];
if (sa[i-1]>m) tt=n-1-sa[i-1];else tt=m-sa[i-1];
ans2+=tt-min(tm,min(tt,height[i]));
}
cout<<(ans1+ans2)/2<<endl;
return 0;
}