zoukankan      html  css  js  c++  java
  • [BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组

      
      a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
    现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?  
     
      应该算是后缀数组比较简单的应用了吧...
      首先把所有的串都接起来,中间用不同的分隔符隔开
      然后进行后缀数组将sa,rank,height等数组求出来
      最后枚举每一个点名串,以rank[点名串起点]开始向左和向右拓展
      这里的拓展是指在sa的下标里拓展
      边统计边累计每个喵星人的点到次数
      为了避免一次点名中统计到一个喵星人多次,以及一个喵星人一次点名却统计了多次
      (实际上二者是一样的...)
      都可以用一个标号数组来处理
      然而这个标号数组如果每次fillchar显然不现实...因为太慢...
      然后就运用到KM算法里顶标更新的思想
      当然,再做一次然后把数组还原也是可以的
     
      另外在BZ上PE了一发...行末注意不能留有空格
      1 program bzoj2754;
      2 const INF = 100007;maxn = 400010;
      3 var tota,totb,i,cnt,n,x,j:longint;
      4     a,rank,s,tmp,sa,height,pos,ter,len,vis,ans:array[-1..maxn]of longint;
      5 
      6 function max(a,b:longint):longint;
      7 begin
      8     if a>b then exit(a) else exit(b);
      9 end;
     10 
     11 procedure Suffix_Array;
     12 var sz,i,j,p,v0,v1,v00,v01:longint;
     13 begin
     14     sz:=max(n,INF+10000);
     15     for i:=0 to sz do s[i]:=0;
     16     for i:=0 to n-1 do rank[i]:=a[i];
     17     for i:=0 to n-1 do inc(s[rank[i]]);
     18     for i:=1 to sz do inc(s[i],s[i-1]);
     19     for i:=n-1 downto 0 do
     20     begin
     21         dec(s[rank[i]]);
     22         sa[s[rank[i]]]:=i;
     23     end;
     24     j:=1;
     25     while j<=n do
     26     begin
     27         p:=0;
     28         for i:=n-j to n-1 do
     29         begin
     30             tmp[p]:=i;inc(p);
     31         end;
     32         for i:=0 to n-1 do if sa[i]-j>=0 then
     33         begin
     34             tmp[p]:=sa[i]-j;inc(p);
     35         end;
     36         for i:=0 to sz do s[i]:=0;
     37         for i:=0 to n-1 do inc(s[rank[i]]);
     38         for i:=1 to sz do inc(s[i],s[i-1]);
     39         for i:=n-1 downto 0 do
     40         begin
     41             dec(s[rank[tmp[i]]]);
     42             sa[s[rank[tmp[i]]]]:=tmp[i];
     43         end;
     44         p:=0;tmp[sa[0]]:=0;
     45         for i:=1 to n-1 do
     46         begin
     47             v0:=sa[i-1];v1:=sa[i];
     48             if v0+j<n then v00:=rank[v0+j] else v00:=-1;
     49             if v1+j<n then v01:=rank[v1+j] else v01:=-1;
     50             if (rank[v0]=rank[v1])and(v00=v01) then tmp[sa[i]]:=p else
     51             begin
     52                 inc(p);tmp[sa[i]]:=p;
     53             end;
     54         end;
     55         for i:=0 to n-1 do rank[i]:=tmp[i];
     56         j:=j << 1;
     57     end;
     58 end;
     59 
     60 function compare(i,j,x:longint):longint;
     61 begin
     62     while (i+x-1<n)and(j+x-1<n)and(a[i+x-1]=a[j+x-1]) do inc(x);
     63     exit(x-1);
     64 end;
     65 
     66 procedure calc_height;
     67 var i:longint;
     68 begin
     69     if rank[0]=0 then height[0]:=0 else height[0]:=compare(0,sa[rank[0]-1],1);
     70     for i:=1 to n-1 do
     71     if rank[i]=0 then height[i]:=0 else height[i]:=compare(i,sa[rank[i]-1],max(height[i-1],1));
     72 end;
     73 
     74 function solve(x,y:longint):longint;
     75 var i,tot:longint;
     76 begin
     77     x:=rank[x];i:=x;tot:=0;
     78     while (i>=1)and(height[sa[i]]>=y) do
     79     begin
     80         if (pos[sa[i-1]]<>0)and(vis[pos[sa[i-1]]]<>x) then
     81         begin
     82             inc(tot);vis[pos[sa[i-1]]]:=x;inc(ans[pos[sa[i-1]]]);
     83         end;
     84         dec(i);
     85     end;
     86     i:=x+1;
     87     while (i<n)and(height[sa[i]]>=y) do
     88     begin
     89         if (pos[sa[i]]<>0)and(vis[pos[sa[i]]]<>x) then
     90         begin
     91             inc(tot);vis[pos[sa[i]]]:=x;inc(ans[pos[sa[i]]]);
     92         end;
     93         inc(i);
     94     end;
     95     exit(tot);
     96 end;
     97 
     98 begin
     99     readln(tota,totb);cnt:=0;n:=-1;
    100     for i:=1 to tota do
    101     begin
    102         read(x);for j:=1 to x do begin inc(n);read(a[n]);inc(a[n],INF);pos[n]:=i;end;
    103         inc(cnt);inc(n);a[n]:=cnt;
    104         read(x);for j:=1 to x do begin inc(n);read(a[n]);inc(a[n],INF);pos[n]:=i;end;
    105         inc(cnt);inc(n);a[n]:=cnt;
    106     end;
    107     for i:=1 to totb do
    108     begin
    109         ter[i]:=n+1;
    110         read(x);for j:=1 to x do begin inc(n);read(a[n]);inc(a[n],INF);end;
    111         len[i]:=x;
    112         inc(cnt);inc(n);a[n]:=cnt;
    113     end;
    114     fillchar(vis,sizeof(vis),255);
    115     inc(n);
    116     suffix_array;
    117 
    118     calc_height;
    119     fillchar(ans,sizeof(ans),0);
    120     for i:=1 to totb do writeln(solve(ter[i],len[i]));
    121     for i:=1 to tota-1 do write(ans[i],' ');writeln(ans[tota]);
    122 end.
     
     
  • 相关阅读:
    [转] zigbee的低功耗
    手机显示电量原理
    TinyOS总结(一)
    KingPaper初探redist 之redis设置分析
    KingPaper初探redis之redis在window xp下的安装
    Web开发必知的八种隔离级别
    目前国内著名的维客(wiki)网站
    SSH Secure Shell Client
    Java线程:volatile关键字
    JDK1.6(JDK6.0) 新特性
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4478945.html
Copyright © 2011-2022 走看看