解题思路:
我们可以先用manacher和并查集处理出哪些位置必须要填相同的字母,再把每个并查集看做一个点,再向和该并查集必须填不同字母的并查集连边,可以证明这样构造出的是一个弦图,详见:http://foreseeable97.logdown.com/posts/194507-herbicidalontak2010palindromic-equivalence
然后就成了弦图染色问题了,求一边完美消除序列,倒着处理即可,注意有重边。
ps:这道题数据貌似1-n这个排列总是完美消除序列,所以就不用去求了,不知是数据水还是有规律……
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<queue>
#define ll unsigned long long
using namespace std;
const int N=1000005,p=1e9+7;
int n,m,ans=1,fa[N],r[N<<1],vis[N];
int tot,first[N],nxt[N<<2],to[N<<2];
char t[N],s[N<<1];
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int i,int j)
{
if(i&1||j&1||!i||j>2*n)return;
fa[find(i>>1)]=find(j>>1);
}
void add(int x,int y)
{
nxt[++tot]=first[x],first[x]=tot,to[tot]=y;
}
void manacher()
{
int po=0,mx=0;
for(int i=1;i<=m;i++)
{
if(mx>i)r[i]=min(mx-i,r[2*po-i]);
else r[i]=1;
while(s[i+r[i]]==s[i-r[i]])
{
merge(i+r[i],i-r[i]);
r[i]++;
}
if(i+r[i]>mx)mx=i+r[i],po=i;
}
for(int i=1;i<=m;i++)
if(i-r[i]>0&&i+r[i]<=2*n&&!((i-r[i])&1))
{
int x=find((i-r[i])>>1),y=find((i+r[i])>>1);
add(x,y),add(y,x);
}
}
int main()
{
//freopen("lx.in","r",stdin);
scanf("%s",t+1);
n=strlen(t+1);
s[0]='!',s[++m]='#';
for(int i=1;i<=n;i++)
s[++m]=t[i],s[++m]='#';
s[++m]='?';
for(int i=1;i<=n;i++)fa[i]=i;
manacher();
for(int i=1;i<=n;i++)
{
if(find(i)!=i)continue;
vis[i]=i;int cnt=26;
for(int e=first[i];e;e=nxt[e])
if(vis[to[e]]&&vis[to[e]]!=i)
vis[to[e]]=i,cnt--;
ans=1ll*ans*cnt%p;
}
cout<<ans;
return 0;
}