【BZOJ3103】【BZOJ3350】Palindromic Equivalence/相似回文串(manacher)(弦图)

给出一个由小写字母组成的字符串 S S S,问有多少由小写字母 构成的字条串 S ′ S' S,满足

  1. ∣ S ∣ ′ = ∣ S ∣ |S|'=|S| S=S
  2. 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 &lt; j &lt; k i &lt; j&lt; 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 &lt; j &lt; k i &lt;j &lt; 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,k1]是一个回文串。由 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,j1]也是一个回文串。

由于 a [ i + 1 , k − 1 ] a[i+1,k-1] a[i+1,k1] a [ i + 1 , j − 1 ] a[i+1,j-1] a[i+1,j1]是回文串,则 a [ k − j + i + 1 , k − 1 ] a[k-j+i+1,k-1] a[kj+i+1,k1]也是回文串,但是我们并不知道 a [ k − j + i + 1 , k − 1 ] a[k-j+i+1,k-1] a[kj+i+1,k1]是否是极长回文串。现在由于回文串,有 a [ k − j + i ] = a [ j ] a[k-j+i]=a[j] a[kj+i]=a[j]

考虑 a [ k − j + i + 1 , k − 1 ] a[k-j+i+1,k-1] a[kj+i+1,k1]是否是极长回文串我们有以下两种关系:

a [ k − j + i ] = a [ k ] a[k-j+i]=a[k] a[kj+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[kj+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 1n的一个任意排列。

随便染色就行了。


代码:

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值