给出一个由小写字母组成的字符串SSS,问有多少由小写字母 构成的字条串S′S'S′,满足
- ∣S∣′=∣S∣|S|'=|S|∣S∣′=∣S∣
- S′[L..R]S'[L..R]S′[L..R]是回文串,当且仅当S[L..R]S[L..R]S[L..R]是回文串
题解:
直接利用manacher可以推得O(n)O(n)O(n)组相等关系和不等关系。
回文串内部的对称位置扔到并查集,每个极长回文串的两端向外必然是不等,我们连边表示这个限制。
下面证明这个图最终连出来是个弦图。
设i<j<ki < j< ki<j<k,假设已经有a[i]!=a[k]a[i]!=a[k]a[i]!=a[k],我们现在希望证明,如果a[i]!=a[j]a[i]!=a[j]a[i]!=a[j],要么a[j]a[j]a[j]和a[k]a[k]a[k]在并查集的同一集合中,要么a[j]!=a[k]a[j]!=a[k]a[j]!=a[k]。
其实这个东西看着相当奇怪,发现好像就是要证明一定有a[j]=a[k]a[j]=a[k]a[j]=a[k]或者a[j]!=a[k]a[j]!=a[k]a[j]!=a[k]?(你可能就会觉得这不是显而易见的吗)
但是仔细想一想,a[j]a[j]a[j]和a[k]a[k]a[k]之间是有可能没有任何限制关系的。
所以现在开始证明:
设i<j<ki <j < ki<j<k,如果有a[i]!=a[k]a[i]!=a[k]a[i]!=a[k]且a[i]!=a[j]a[i]!=a[j]a[i]!=a[j],则必然有a[j]=a[k]a[j]=a[k]a[j]=a[k]或a[j]!=a[k]a[j]!=a[k]a[j]!=a[k]。
首先根据连边策略,由a[i]!=a[k]a[i]!=a[k]a[i]!=a[k],我们知道a[i+1,k−1]a[i+1,k-1]a[i+1,k−1]是一个回文串。由a[i]!=a[j]a[i]!=a[j]a[i]!=a[j],则a[i+1,j−1]a[i+1,j-1]a[i+1,j−1]也是一个回文串。
由于a[i+1,k−1]a[i+1,k-1]a[i+1,k−1]和a[i+1,j−1]a[i+1,j-1]a[i+1,j−1]是回文串,则a[k−j+i+1,k−1]a[k-j+i+1,k-1]a[k−j+i+1,k−1]也是回文串,但是我们并不知道a[k−j+i+1,k−1]a[k-j+i+1,k-1]a[k−j+i+1,k−1]是否是极长回文串。现在由于回文串,有a[k−j+i]=a[j]a[k-j+i]=a[j]a[k−j+i]=a[j]。
考虑a[k−j+i+1,k−1]a[k-j+i+1,k-1]a[k−j+i+1,k−1]是否是极长回文串我们有以下两种关系:
a[k−j+i]=a[k]a[k-j+i]=a[k]a[k−j+i]=a[k],则a[k]=a[j]a[k]=a[j]a[k]=a[j],a[k]a[k]a[k]和a[j]a[j]a[j]在并查集的同一个集合里面。
否则a[k−j+i]!=a[k]a[k-j+i]!=a[k]a[k−j+i]!=a[k],则a[k]!=a[j]a[k]!=a[j]a[k]!=a[j],a[k]a[k]a[k]与a[j]a[j]a[j]之间存在连边。
所以这不仅是个弦图,它的每个连通块还是个完全图。
完全图的完美消除序列是1−n1-n1−n的一个任意排列。
随便染色就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
cs int mod=1e9+7;
cs int N=1e6+6;
int fa[N];
inline int get_fa(int x){return fa[x]==x?x:fa[x]=get_fa(fa[x]);}
inline void merge(int x,int y){
if((x&1)||get_fa(x>>=1)==get_fa(y>>=1))return ;
fa[fa[x]]=fa[y];
}
int last[N],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
if(!u||!v||(u&1))return ;
nxt[++ecnt]=last[u>>1],last[u>>1]=ecnt,to[ecnt]=v>>1;
}
int n,m;
char s[N<<1],a[N];
int R[N<<1],r,p;
inline void manacher(){
R[1]=1;
for(int re i=2;i<m;++i){
for(R[i]=r>i?std::min(r-i,R[2*p-i]):1;s[i-R[i]]==s[i+R[i]];++R[i])merge(i+R[i],i-R[i]);
addedge(i+R[i],i-R[i]);
if(i+R[i]>r)r=i+R[i],p=i;
}
}
bool sol[N];int vis[N];
signed main(){
// freopen("equ.in","r",stdin);//freopen("equ.out","w",stdout);
scanf("%s",a+1);n=strlen(a+1);
for(int re i=1;i<=n;++i)s[i<<1]=a[i],s[i<<1|1]='#',fa[i]=i;s[0]='!',s[1]='#',s[m=(n+1)<<1]='*';
manacher();
int ans=1;
for(int re i=1;i<=n;++i)if(!sol[get_fa(i)]){
int cnt=26;
for(int re e=last[i],v=to[e];e;v=to[e=nxt[e]])
if(sol[get_fa(v)]&&vis[get_fa(v)]<i)vis[fa[v]]=i,--cnt;
sol[fa[i]]=true;
ans=(ll)ans*cnt%mod;
}
std::cout<<ans<<"\n";
return 0;
}