首页 > 代码库 > BZOJ4566[HAOI2016]找相同字符
BZOJ4566[HAOI2016]找相同字符
Description
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两
个子串中有一个位置不同。
Input
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
Output
输出一个整数表示答案
Sample Input
aabb
bbaa
bbaa
Sample Output
10
题解:
将两个字符串共同建出一个SAM(即先用A串建出SAM,再将last指为root,用B串继续建)。
这样,我们只用知道每个节点在A串中对应几个串、在B串中对应几个串(即在A、B中的size),在每次遍历到时相乘加到答案上。
求size的方法是将A、B串分别输入到自动机中,得到初始size1、size2,然后分别在pre树中dfs求出最终size1、size2。
访问节点i对答案的贡献为size1[i]*size2[i],可以记忆化搜索统计答案,或利用某个性质(升级版:只有长度大于等于k的子串才被统计)。
代码:
var i,j,k,l,n,m,now,last,t,cnt:longint; ans:int64; a:array[0..800005,‘a‘..‘z‘]of longint; pre,step,c:array[0..800005]of longint; size1,size2:array[0..800005]of int64; b:array[0..800005,1..2]of longint; s1,s2:ansistring; ch:char; function max(x,y:longint):longint; begin if x>y then exit(x); exit(y); end; procedure ss1(x,y:longint); begin inc(size1[x]); if y>=length(s1)then exit; ss1(a[x,s1[y+1]],y+1); end; procedure ss2(x,y:longint); begin inc(size2[x]); if y>=length(s2)then exit; ss2(a[x,s2[y+1]],y+1); end; procedure ss3(x:longint); var i:longint; begin i:=c[x]; while i>0 do begin ss3(b[i,1]); size1[x]:=size1[x]+size1[b[i,1]]; size2[x]:=size2[x]+size2[b[i,1]]; i:=b[i,2]; end; end; begin readln(s1); readln(s2); pre[0]:=-1; m:=0; last:=0; for i:=1 to length(s1) do begin inc(m); now:=m; step[now]:=step[last]+1; while(last<>-1)and(a[last,s1[i]]=0)do begin a[last,s1[i]]:=now; last:=pre[last]; end; if last=-1 then begin pre[now]:=0; last:=now; continue; end; if step[last]+1=step[a[last,s1[i]]] then begin pre[now]:=a[last,s1[i]]; last:=now; continue; end; j:=a[last,s1[i]]; inc(m); a[m]:=a[j]; pre[m]:=pre[j]; step[m]:=step[last]+1; pre[j]:=m; pre[now]:=m; while last<>-1 do begin if a[last,s1[i]]=j then a[last,s1[i]]:=m else break; last:=pre[last]; end; last:=now; end; last:=0; for i:=1 to length(s2) do begin inc(m); now:=m; step[now]:=step[last]+1; while(last<>-1)and(a[last,s2[i]]=0)do begin a[last,s2[i]]:=now; last:=pre[last]; end; if last=-1 then begin pre[now]:=0; last:=now; continue; end; if step[last]+1=step[a[last,s2[i]]] then begin pre[now]:=a[last,s2[i]]; last:=now; continue; end; j:=a[last,s2[i]]; inc(m); a[m]:=a[j]; pre[m]:=pre[j]; step[m]:=step[last]+1; pre[j]:=m; pre[now]:=m; while last<>-1 do begin if a[last,s2[i]]=j then a[last,s2[i]]:=m else break; last:=pre[last]; end; last:=now; end; cnt:=0; for i:=1 to m do begin inc(cnt); b[cnt,1]:=i; b[cnt,2]:=c[pre[i]]; c[pre[i]]:=cnt; end; ss1(0,0); ss2(0,0); ss3(0); ans:=0; for i:=1 to m do ans:=ans+(size1[i]*size2[i])*(step[i]-max(k,step[pre[i]]+1)+1); writeln(ans); end.
BZOJ4566[HAOI2016]找相同字符
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。