您的位置:首页 > 其它

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

2018-03-25 17:08 585 查看


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 (T≤5),
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

2015 Multi-University Training Contest 5

      大致题意,给你两个字符串,然后从第一个字符串里面取出一个子串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
,sa
,right
;
struct node{int ch[26],len,fa;} T
;
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
,s2
;
LL dp1
,dp2
;

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));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: