【BZOJ3350】相似回文串

Description

记S(i,j)为字符串S的第i个字母到第j个字母组成的子串。
给出一个长度为n由小写英文字母组成的字符串A。
若字符串B也由小写英文字母组成,长度为n,且对于任意1<=i< j<=n有:若A(i,j)是回文串,B(i,j)也是回文串;若A(i,j)不是回文串,B(i,j)也不是回文串。那么我们称B与A是ayq相似的。
求有多少个字符串与A ayq相似?输出答案对1000000007取模的余数。

Input

输入1行一个字符串A

Output

输出一行一个数表示所求答案

Sample Input

abcba

Sample Output

15600

HINT

对于100%的数据,n<=1000000

Source

和3103是双倍经验题
用马拉车找回文串,对于一个确定的回文子串我们可以把他当成一个相等关系,其他当成不等关系.
有相等关系的点可以用UFS合并一下,不等的连边
连完边就变成了图的染色问题
这里弦图染色不太会搞..而且发现自己在APIO2014回文串里写(chao)的黄学长的马拉车模板是问题的(Rivendell说那题能拍出错来QAQ
然后就换了一种模板姿势

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 1000010
#define P 1000000007
#define LL long long
using namespace std;
int n,newn,ans=1,top;
char ch[MAXN],c[MAXN<<1];
int f[MAXN],col[MAXN];
int p[MAXN<<1],maxn,id;
int vis[MAXN];
int find(int x) {   return f[x]==x?x:f[x]=find(f[x]);   }
void Union(int a,int b)
{
    if (a&1)    return;
    a>>=1;b>>=1;
    int x=find(a),y=find(b);
    if (x!=y)   f[x]=y;
}
struct edge
{
    int to;
    edge *next;
}e[MAXN<<1],*prev[MAXN];
void insert(int u,int v)
{
    if (u&1||!u||!v)    return;
    u>>=1;v>>=1;e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];
}
int main()
{
    scanf("%s",ch+1);int n=strlen(ch+1),newn=(n+1)<<1;
    c[0]='&';c[1]='#';c[newn]='*';p[1]=1;
    for (int i=1;i<=n;i++)  f[i]=i;
    for (int i=1;i<=n;i++)  c[i<<1]=ch[i],c[i<<1|1]='#';
    for (int i=2;i<newn;i++)
    {
        p[i]=maxn>i?min(p[2*id-i],maxn-i):1;
        while (c[i-p[i]]==c[i+p[i]])    Union(i+p[i],i-p[i]),p[i]++;
        insert(i+p[i],i-p[i]);
        if (i+p[i]>maxn)    maxn=i+p[i],id=i;
    }
    for (int x=1;x<=n;x++)
        if (!col[find(x)])
        {
            int cnt=26;
            for (edge *i=prev[x];i;i=i->next)
                if (col[find(i->to)]&&vis[f[i->to]]<x)  vis[f[i->to]]=x,cnt--;
            ans=(int)((LL)ans*cnt%P);col[f[x]]=1;
        }
    cout<<ans<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值