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