[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.

 

 
 
posted @ 2015-05-05 13:54  mjy0724  阅读(178)  评论(0编辑  收藏  举报