bzoj3413
SAM好题,显然我们不能与每个后缀都去算LCP
考虑对询问串每一位算贡献,先构建出逆序构建自动机,这样我们得到了原串的后缀树(parent树)
根据parent树的定义,一个节点对应字符串出现的位置对应该节点的right集合也就是子树right集合的并
某些节点代表了一个后缀,我们从开头到结尾编号为1~n;这样求出每个节点的子树内,代表后缀的节点所代表的后缀编号最小是多少,记作mi[]
然后对于每个询问串在自动机上匹配(逆序),设最终匹配到的点为x
由于每个子串一定是某个后缀的某个前缀
如果匹配成功了,说明匹配到mi[x]这个后缀就结束了,否则会一直匹配下去,我们假设匹配到n+1结束
设最终匹配到的后缀为m,显然,从x到root上我们计算每条边的贡献
对于边(fa[a],a),边上的每个字符的比较次数贡献显然就是a子树内代表后缀编号小于等于m的节点个数
裸的想法可以用dfs序+主席树来完成
最后我们答案还要+x-1,因为比较失败也算是一次比较……
type node=record
po,next:longint;
end;
point=record
l,r,s:longint;
end; var tree:array[..*] of point;
e:array[..] of node;
go:array[..,''..''] of longint;
mi,b,h,p,l,r,fa,mx,w:array[..] of longint;
cl,n,m,x,y,i,j,k,last,t,len:longint;
fl:boolean;
s:ansistring;
ans:int64; function lowbit(x:longint):longint;
begin
exit(x and (-x));
end; function min(a,b:longint):longint;
begin
if a>b then exit(b) else exit(a);
end; procedure ins(x,y:longint);
begin
inc(len);
e[len].po:=y;
e[len].next:=p[x];
p[x]:=len;
end; procedure add(c:char);
var p,q,np,nq:longint;
begin
p:=last;
inc(t); np:=t; last:=t;
mx[np]:=mx[p]+;
w[np]:=i;
while (p<>) and (go[p,c]=) do
begin
go[p,c]:=np;
p:=fa[p];
end;
if p= then fa[np]:=
else begin
q:=go[p,c];
if mx[q]=mx[p]+ then fa[np]:=q
else begin
inc(t); nq:=t;
mx[nq]:=mx[p]+;
go[nq]:=go[q];
fa[nq]:=fa[q];
fa[q]:=nq; fa[np]:=nq;
while go[p,c]=q do
begin
go[p,c]:=nq;
p:=fa[p];
end;
end;
end;
end; procedure dfs(x:longint);
var i,y:longint;
begin
inc(len);
b[len]:=x;
mi[x]:=w[x];
if w[x]= then mi[x]:=;
// writeln(x,' ',fa[x],':',w[x]);
l[x]:=len;
i:=p[x];
while i<> do
begin
y:=e[i].po;
dfs(y);
mi[x]:=min(mi[x],mi[y]);
i:=e[i].next;
end;
r[x]:=len;
// writeln(mi[x]);
end; function build(l,r:longint):longint;
var m,q:longint;
begin
inc(len);
if l=r then exit(len)
else begin
q:=len;
m:=(l+r) shr ;
tree[q].l:=build(l,m);
tree[q].r:=build(m+,r);
exit(q);
end;
end; function work(l,r,last,x:longint):longint;
var m,q:longint;
begin
inc(len);
q:=len;
if l=r then tree[q].s:=tree[last].s+
else begin
m:=(l+r) shr ;
if x<=m then
begin
tree[q].r:=tree[last].r;
tree[q].l:=work(l,m,tree[last].l,x);
end
else begin
tree[q].l:=tree[last].l;
tree[q].r:=work(m+,r,tree[last].r,x);
end;
tree[q].s:=tree[tree[q].l].s+tree[tree[q].r].s;
end;
exit(q);
end; function ask(l,r,p,q:longint):longint;
var m:longint;
begin
if (x>=r) then exit(tree[q].s-tree[p].s)
else begin
m:=(l+r) shr ;
if x<=m then exit(ask(l,m,tree[p].l,tree[q].l))
else exit(tree[tree[q].l].s-tree[tree[p].l].s+ask(m+,r,tree[p].r,tree[q].r));
end;
end; begin
readln(n);
readln(s);
last:=; t:=;
for i:=n downto do
add(s[i]);
for i:= to t do
if fa[i]<> then ins(fa[i],i);
len:=;
dfs();
readln(m);
len:=;
h[]:=build(,n);
for i:= to t do
if w[b[i]]= then h[i]:=h[i-]
else h[i]:=work(,n,h[i-],w[b[i]]);
for i:= to m do
begin
readln(s);
len:=length(s);
j:=;
fl:=true;
cl:=;
for k:=len downto do
if go[j,s[k]]= then
begin
while (go[j,s[k]]=) and (j>) do
begin
j:=fa[j];
cl:=mx[j];
end;
if j= then j:=
else begin
inc(cl);
j:=go[j,s[k]];
end;
fl:=false;
end
else begin
inc(cl);
j:=go[j,s[k]];
end; //cl表示询问串从头开始最长匹配的长度
if fl then x:=mi[j] else x:=n+;
ans:=;
if j> then
begin
y:=cl-mx[fa[j]]; // 这里要注意
ans:=ans+int64(y)*int64(ask(,n,h[l[j]-],h[r[j]]));
j:=fa[j];
end;
while j> do
begin
y:=mx[j]-mx[fa[j]];
ans:=ans+int64(y)*int64(ask(,n,h[l[j]-],h[r[j]]));
j:=fa[j];
end;
writeln(ans+x-);
end;
end.
bzoj3413的更多相关文章
- 【BZOJ3413】匹配(后缀自动机,线段树合并)
[BZOJ3413]匹配(后缀自动机,线段树合并) 题面 BZOJ 题解 很好的一道题目. 做一个转化,匹配的次数显然就是在可以匹配的区间中,每个前缀的出现次数之和. 首先是空前缀的出现次数,意味着你 ...
- 【BZOJ3413】匹配 离线+后缀树+树状数组
[BZOJ3413]匹配 Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一 ...
- BZOJ3413 : 匹配
FDUSC前刷刷题吧.. 本题每个询问就是说将询问串与主串每个后缀匹配,若匹配成功则结束,否则加上lcp的长度 对主串建立后缀树,并用主席树维护DFS序 对于每个询问串,找到最后走到的点fin_nod ...
- BZOJ3413: 匹配(后缀自动机 线段树合并)
题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...
- BZOJ3413: 匹配(后缀自动机,Parent树,线段树合并)
Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一个由0到9组成的字符串s, ...
随机推荐
- android 中怎么控制checkbox中文本与左侧box的距离
使用paddingLeft属性可以控制宽度.默认比较宽 效果如图:
- 常用git 命令
1.取消跟踪某些文件或文件夹: 删除文件: $git rm --cached FILENAME 删除文件夹: $git rm -r --cached Path 2.忽略某些文件或文件夹 $vi .gi ...
- 【转】使用JIRA搭建企业问题跟踪系统【个人推荐】
免责声明: 本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除. 原文作者:Judy Shen的专栏 原文地址:使用JIRA搭建企业问题跟踪系统 ...
- jquery ajax对特殊字符进行转义防止js注入使用示例
在使用ajax进行留言的时候,出现了一个问题.因为留言内容写完之后,通过ajax提交内容,同时使用js把留言的内容添加到页面上来.浏览留言的时候也是通过ajax请求,然后再显示的.这样,如果有人在留言 ...
- 【POJ】【2068】Nim
博弈论/DP 这是Nim?这不是巴什博奕的变形吗…… 我也不会捉啊,不过一看最多只有20个人,每人最多拿16个石子,总共只有8196-1个石子,范围好像挺小的,嗯目测暴力可做. so,记忆化搜索直接水 ...
- ssh连接慢
suse刚装完,开始用ssh的时候,总会遇到这样的问题:输入了用户名以后,等半天才出输入密码的框,很是急人.这是dns反查造成的.解决方法:编辑 /etc/ssh/sshd_conf , 将 #Use ...
- [C/CPP系列知识] 那些程序C语言可以编译通过但C++无法编译成功 Write a C program that won’t compile in C++
http://www.geeksforgeeks.org/write-c-program-wont-compiler-c/ 1) C++中在函数声明之前调用一个函数会引发错误,但是在C中有可能可以. ...
- 使用静态变量的方法求n!
下面的程序可以输出1-5的阶乘值,如果需要把5改为n,则可求出1-n的阶乘值. void main() { setvbuf(stdout,NULL,_IONBF,); int fac(int n); ...
- PHP 开发中的外围资源性能分析(一)
暂且不讨论「PHP 是不是最好的编程语言」,本文我们将分别分析一下在 PHP 程序的后端外围资源和前端外围资源,它们对整个 PHP Web 应用体验的影响,这往往比语言本身大得多. 首先,后端外围资源 ...
- Javascript中的Cookie操作
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...