给出一个由小写字母组成的字符串 S S S,问有多少由小写字母 构成的字条串 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 < k i < j< k i<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 < k i <j < k i<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 − n 1-n 1−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;
}