HDU 5343 MZL's Circle Zhou(后缀自动机+记忆化搜索)

MZL's Circle Zhou

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 506    Accepted Submission(s): 212

Problem Description
MZL's Circle Zhou is good at solving some counting problems. One day, he comes up with a counting problem:
You are given two strings a,b which consist of only lowercase English letters. You can subtract a substring x (maybe empty) from string a and a substring y (also maybe empty) from string b, and then connect them as x+y with x at the front and y at the back. In this way, a series of new strings can be obtained.
The question is how many different new strings can be obtained in this way.
Two strings are different, if and only if they have different lengths or there exists an integer i such that the two strings have different characters at position i.
 

Input
The first line of the input is a single integer T (T5), indicating the number of testcases.
For each test case, there are two lines, the first line is string a, and the second line is string b. 1<=|a|,|b|<=90000.
 

Output
For each test case, output one line, a single integer indicating the answer.
 

Sample Input
 
  
2acbcccccabcbbbabbababbababbaaaabbbbabbaaaabaabbabbabbbaaabaababbaabbabbaaaabbbaababbabbabababaaaaabbaabbaabbaab
 

Sample Output
 
  
135557539
 

Author
SXYZ
 

Source



      大致题意,给你两个字符串,然后从第一个字符串里面取出一个子串X,从第二个字符串里面取出一个子串Y,两个拼接在一起组成新的字符串,其中X、Y都可以是空串,问有多少个这样不同的串。

        如果整体来思考不同的X+Y的个数,会发现找不到突破口。我们可以考虑X+Y为什么会有重复的。举个例子ababc,可以由ab+abc或则a+babc组成。重复的原因在于在第一个串中可以找到ab,也可以找到a,而如果a可以构成这个拼接串,那么ab也构成这个拼接串。所以说,为了避免重复,我们可以在第一个串中找最长的点,即走到某个点x,然后这个点不能走到字符'a',那么对于字符'a'来说,x这个点就是最长的,在另一个串中找'a'开头的子串个数,这些就是点x的可以匹配到的个数。
        具体来说,对于两个子串各自建立后缀自动机,利用后缀自动机保存所有子串的性质。先在第一个自动机上面遍历,遍历到一个不能走到一个特定字符的点,然后再到另一个自动机上遍历找到以该特定字符开头的所有子串个数。这个个数就是这一个节点的贡献。统计所有的贡 献和即可。
        由于是两个自动机,然后涉及到相互的遍历,所以如果直接暴力遍历,复杂度可以退化到O(N^2)。但是考虑到不同时期遍历同一个点的贡献相同,所以我们可以用记忆化搜索来把保存贡献,每个点只需要计算一次,做到O(N)复杂度。另外,本题数据量较大,需要用到unsigned long long。具体见代码:
#include<bits/stdc++.h>
#define LL unsigned long long
#define N 200010
using namespace std;

struct Suffix_Automation
{
    int tot,cur,n,c[N],sa[N],right[N];
    struct node{int ch[26],len,fa;} T[N];
    void init(){cur=tot=1;memset(T,0,sizeof(T));}

    void ins(int x,int id)
    {
        int p=cur;cur=++tot;T[cur].len=id;right[cur]++;
        for(;p&&!T[p].ch[x];p=T[p].fa) T[p].ch[x]=cur;
        if (!p) {T[cur].fa=1;return;}int q=T[p].ch[x];
        if (T[p].len+1==T[q].len) {T[cur].fa=q;return;}
        int np=++tot; memcpy(T[np].ch,T[q].ch,sizeof(T[q].ch));
        T[np].fa=T[q].fa; T[q].fa=T[cur].fa=np; T[np].len=T[p].len+1;
        for(;p&&T[p].ch[x]==q;p=T[p].fa) T[p].ch[x]=np;
    }

} X,Y;

char s1[N],s2[N];
LL dp1[N],dp2[N];

LL dfs2(int x)
{
    if (!x) return 0;
    LL res=1; if (dp2[x]) return dp2[x];
    for(int i=0;i<26;i++)
    {
        int nxt=Y.T[x].ch[i];
        if (nxt) res+=dfs2(nxt);
    }
    return dp2[x]=res;
}

LL dfs1(int x)
{
    LL res=1;
    if (dp1[x]) return dp1[x];
    for(int i=0;i<26;i++)
    {
        int nxt=X.T[x].ch[i];
        if (nxt) res+=dfs1(nxt);
            else res+=dfs2(Y.T[1].ch[i]);
    }
    return dp1[x]=res;
}

int main()
{
    int T_T;
    cin>>T_T;
    while(T_T--)
    {
        X.init(); Y.init();
        scanf("%s%s",s1,s2);
        memset(dp1,0,sizeof(dp1));
        memset(dp2,0,sizeof(dp2));
        for(int i=0;s1[i];i++) X.ins(s1[i]-'a',i+1);
        for(int i=0;s2[i];i++) Y.ins(s2[i]-'a',i+1);
        printf("%I64u\n",dfs1(1));
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值