JZOJ 3887. 【长郡NOIP2014模拟10.22】字符串查询

题目

Description
给定n个字符串和q个询问
每次询问在这n个字符串中,有多少个字符串同时满足
1. 字符串a是它的前缀
2. 字符串b是它的后缀
Input
第一行两个数n,q ,表示给定字符串数和询问数
接下来n行每行一个字符串
再接下来q组询问,每组询问2行,分别表示两个字符串a,b,意义上述
Output
q行每行一个数,表示有多少个字符串满足条件
Sample Input
4 2
abc
bac
ac
acc
a
c
ba
ac
Sample Output
3
1
Data Constraint
100%数据满足n,q≤50000,字符串长度丌超过100,任意两串最长公共前缀较短
字符串全部由小写字母a到j组成,行末保证没有多余字符,没有多余的空行,没有空串

题解

我们可以慢慢地观察到,以某个串为前缀的所有字符串一定是连续的一段,后缀同理。
所以现在我们我们有一个字符串a。
先将所有字符串按照前缀排个序,那么设a的排名为x,再将所有字符串按照后缀排个序,那么设a的排名为y。
那么对于一个询问,就是求在前缀中的合法的区间 [l1,r1] 和在后缀中的合法的区间 [l2,r2] 。通过二维偏序统计,将询问按照 [l1,r1] 排序,把第i个字符串的后缀排名 wz[i] 放入树状数组中。然后扫到 l11 的位置时减去从树状数组中搜索的值,扫到 r1 的位置时加上从树状数组中搜索的值。

代码

var qu:array[0..50003,0..4] of longint;
    a,b:array[0..50003] of string;
    ns,c,wz,o,head,ans:array[0..50003] of longint;
    go,next,l,r,xs:array[0..100003] of longint;
    tot,tot1,i,j,n,m:longint;
    a1,b1,c1:string;
procedure lb(x,y,l2,r2,xishu:longint);
begin
    inc(tot);
    go[tot]:=y;
    next[tot]:=head[x];
    head[x]:=tot;
    l[tot]:=l2;
    r[tot]:=r2;
    xs[tot]:=xishu;
end;
function cmp(x,y:string):longint;
var i,fy:longint;
begin
    fy:=length(y);
    for i:=1 to fy do
        if (x[i]>y[i]) then exit(2) else
        if (x[i]<y[i]) then exit(1);
    exit(0);
end;
function lowbit(x:longint):longint;
begin
    exit(x and (-x));
end;
procedure add(k:longint);
begin
    while (k<=n) do
    begin
        inc(c[k]);
        k:=k+lowbit(k);
    end;
end;
function find(k:longint):longint;
var sum:longint;
begin
    sum:=0;
    while (k>0) do
    begin
        inc(sum,c[k]);
        k:=k-lowbit(k);
    end;
    exit(sum);
end;
procedure qsort(l,r:longint);
var i,j:longint;
    mid,t:string;
begin
    i:=l;
    j:=r;
    mid:=a[(l+r) div 2];
    while (i<j) do
    begin
        while (a[i]<mid) do inc(i);
        while (a[j]>mid) do dec(j);
        if i<=j then
        begin
            t:=a[i];
            a[i]:=a[j];
            a[j]:=t;
            inc(i);dec(j);
        end;
    end;
    if (l<j) then qsort(l,j);
    if (i<r) then qsort(i,r);
end;
procedure qsor1(l,r:longint);
var i,j,t1:longint;
    mid,t:string;
begin
    i:=l;
    j:=r;
    mid:=b[(l+r) div 2];
    while (i<j) do
    begin
        while (b[i]<mid) do inc(i);
        while (b[j]>mid) do dec(j);
        if i<=j then
        begin
            t:=b[i];b[i]:=b[j];b[j]:=t;
            t1:=wz[i];wz[i]:=wz[j];wz[j]:=t1;
            inc(i);dec(j);
        end;
    end;
    if (l<j) then qsor1(l,j);
    if (i<r) then qsor1(i,r);
end;
function ef(op:longint):longint;
var i,j,l,r,mid:longint;
begin
    ef:=0;
    l:=1;
    r:=n;
    repeat
        mid:=(l+r)div 2;
        case op of
            0:begin
                  if (cmp(a[mid],a1)=1) then
                  begin
                      ef:=mid;
                      l:=mid+1;
                  end else r:=mid-1;
              end;
            1:begin
                  if (cmp(a[mid],a1)<2) then
                  begin
                      ef:=mid;
                      l:=mid+1;
                  end else r:=mid-1;
              end;
            2:begin
                  if (cmp(b[mid],b1)=1) then
                  begin
                      ef:=mid;
                      l:=mid+1;
                  end else r:=mid-1;
              end;
            3:begin
                  if (cmp(b[mid],b1)<2) then
                  begin
                      ef:=mid;
                      l:=mid+1;
                  end else r:=mid-1;
              end;
        end;
    until l>r;
end;
begin
    readln(n,m);
    for i:=1 to n do readln(a[i]);
    qsort(1,n);
    for i:=1 to n do
    begin
        for j:=1 to length(a[i]) do b[i]:=a[i][j]+b[i];
        a[i]:=a[i]+' ';
        b[i]:=b[i]+' ';
        wz[i]:=i;
    end;
    qsor1(1,n);
    for i:=1 to n do o[wz[i]]:=i;
    for i:=1 to m do
    begin
        readln(a1);
        b1:='';
        readln(c1);
        for j:=1 to length(c1) do b1:=c1[j]+b1;
        qu[i,0]:=ef(0);
        qu[i,1]:=ef(1);
        qu[i,2]:=ef(2);
        qu[i,3]:=ef(3);
        qu[i,4]:=i;
        if (qu[i,1]>qu[i,0])and(qu[i,3]>qu[i,2]) then
        begin
            if (qu[i,0]>0) then lb(qu[i,0],i,qu[i,2],qu[i,3],-1);
            lb(qu[i,1],i,qu[i,2],qu[i,3],1);
        end;
    end;
    for i:=1 to n do
    begin
        add(o[i]);
        j:=head[i];
        while (j<>0) do
        begin
            ans[go[j]]:=ans[go[j]]+(find(r[j])-find(l[j]))*xs[j];
            j:=next[j];
        end;
    end;
    for i:=1 to m do writeln(ans[i]);
end.
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值