BZOJ4566:[HAOI2016]找相同字符——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4566

https://www.luogu.org/problemnew/show/P3181

给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。

广义后缀自动机,两个串各处理他们的size(或right?),然后对结点l排序,对于每个结点他们的size相乘即为答案。

……等等怎么WA了啊。

比如:

aba

abaa

这组数据ans=10。上面的想法是8

每个结点的贡献并不一定是这么算,该节点往左移(直到它的fa为止)的一段也可以匹配。

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
typedef long long ll;
const int N=8e5+5;
struct tree{
    int a[26],fa,l;
}tr[N];
char s[N];
int tot,pos[N];
int a[N],w[N],len;
ll size[2][N];
inline int insert(int p,int c,int id){
    int np=tr[p].a[c];
    if(np&&tr[np].l==tr[p].l+1){
    size[id][np]++;
    return np;
    }
    np=++tot;tr[np].l=tr[p].l+1;
    for(;p&&!tr[p].a[c];p=tr[p].fa)tr[p].a[c]=np;
    if(!p)tr[np].fa=1;
    else{
    int q=tr[p].a[c];
    if(tr[p].l+1==tr[q].l)tr[np].fa=q;
    else{
        int nq=++tot;tr[nq].l=tr[p].l+1;
        memcpy(tr[nq].a,tr[q].a,sizeof(tr[q].a));
        tr[nq].fa=tr[q].fa;tr[q].fa=tr[np].fa=nq;
        for(;p&&tr[p].a[c]==q;p=tr[p].fa)tr[p].a[c]=nq;
    }
    }
    size[id][np]++;
    return np;
}
int main(){
    tot=1;pos[0]=1;
    cin>>s+1;
    int n=strlen(s+1);
    for(int i=1;i<=n;i++)pos[i]=insert(pos[i-1],s[i]-'a',0);
    cin>>s+1;
    len=n;n=strlen(s+1);len=max(len,n);
    for(int i=1;i<=n;i++)pos[i]=insert(pos[i-1],s[i]-'a',1);
    for(int i=1;i<=tot;i++)w[tr[i].l]++;
    for(int i=1;i<=len;i++)w[i]+=w[i-1];
    for(int i=1;i<=tot;i++)a[w[tr[i].l]--]=i;
    ll ans=0;
    for(int i=tot;i>1;i--){
    size[0][tr[a[i]].fa]+=size[0][a[i]];
    size[1][tr[a[i]].fa]+=size[1][a[i]];
    ans+=size[0][a[i]]*size[1][a[i]]*(tr[a[i]].l-tr[tr[a[i]].fa].l);
    }
    printf("%lld\n",ans);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

转载于:https://www.cnblogs.com/luyouqi233/p/8799329.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值