bzoj4516: [Sdoi2016]生成魔咒
Posted OldJang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4516: [Sdoi2016]生成魔咒相关的知识,希望对你有一定的参考价值。
4516: [Sdoi2016]生成魔咒
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 710 Solved: 393
[Submit][Status][Discuss]
Description
魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。
一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。
例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、
[1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都
需要求出,当前的魔咒串 S 共有多少种生成魔咒。
Input
第一行一个整数 n。
第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。
1≤n≤100000。,用来表示魔咒字符的数字 x 满足 1≤x≤10^9
Output
输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量
Sample Input
7
1 2 3 3 3 1 2
1 2 3 3 3 1 2
Sample Output
1
3
6
9
12
17
22
3
6
9
12
17
22
题解
这题就是求有多少个不同子串……不过首先我不会SAM,其次pascal没有set
于是我就用后缀数组+fhqtreap强行写了一发……首先把串反过来跑后缀数组求出h数组,之后每次插入一个字符就是相当于多了一个新后缀,查一下这个后缀在当前已加入的后缀里rank的前驱后继,然后求一下最长公共前缀,后缀长度减去最长公共前缀就是加入一个字符所增加的子串个数
1A赞啊>_<
1 program j01; 2 const maxn=100086; 3 type xx=record w,id:longint; end; 4 var op:array[0..maxn]of xx; 5 sa,tsa,rank,trank,sum,s,mn,h:array[0..maxn]of longint; 6 st:array[0..20,0..maxn]of longint; 7 len,tot,i,l,r,root,k1,k2:longint; 8 t:array[0..maxn]of record f,w,l,r:longint; end; 9 ans:array[0..maxn]of int64; 10 now,tmp:int64; 11 12 procedure swap(var a,b:longint); 13 var c:longint; 14 begin 15 c:=a;a:=b;b:=c; 16 end; 17 18 function max(a,b:longint):longint; 19 begin 20 if a>b then exit(a) else exit(b); 21 end; 22 23 function min(a,b:longint):longint; 24 begin 25 if a<b then exit(a) else exit(b); 26 end; 27 28 procedure qsort(l,r:longint); 29 var i,j,x:longint;y:xx; 30 begin 31 i:=l;j:=r;x:=op[(i+j)div 2].w; 32 repeat 33 while op[i].w<x do inc(i); 34 while x<op[j].w do dec(j); 35 if i<=j then 36 begin 37 y:=op[i];op[i]:=op[j];op[j]:=y; 38 inc(i);dec(j); 39 end; 40 until i>j; 41 if i<r then qsort(i,r); 42 if l<j then qsort(l,j); 43 end; 44 45 procedure disc; 46 var i:longint; 47 begin 48 qsort(1,len); 49 tot:=1;s[op[1].id]:=1; 50 for i:=2 to len do 51 begin 52 if(op[i].w<>op[i-1].w)then inc(tot); 53 s[op[i].id]:=tot 54 end; 55 end; 56 57 procedure getsa; 58 var i,j,m,p:longint; 59 begin 60 fillchar(sum,sizeof(sum),0);m:=tot; 61 for i:=1 to len do rank[i]:=s[i]; 62 for i:=1 to len do inc(sum[rank[i]]); 63 for i:=1 to m do inc(sum[i],sum[i-1]); 64 for i:=len downto 1 do 65 begin 66 sa[sum[rank[i]]]:=i;dec(sum[rank[i]]); 67 end; 68 m:=1;trank[sa[1]]:=1; 69 for i:=2 to len do 70 begin 71 if(rank[sa[i]]<>rank[sa[i-1]])then inc(m); 72 trank[sa[i]]:=m; 73 end; 74 j:=1;rank:=trank; 75 while m<len do 76 begin 77 fillchar(sum,sizeof(sum),0);p:=0; 78 for i:=len-j+1 to len do 79 begin 80 inc(p);tsa[p]:=i; 81 end; 82 for i:=1 to len do 83 if sa[i]>j then 84 begin 85 inc(p);tsa[p]:=sa[i]-j; 86 end; 87 for i:=1 to len do inc(sum[rank[i]]); 88 for i:=1 to m do inc(sum[i],sum[i-1]); 89 for i:=len downto 1 do 90 begin 91 sa[sum[rank[tsa[i]]]]:=tsa[i];dec(sum[rank[tsa[i]]]); 92 end; 93 m:=1;trank[sa[1]]:=1; 94 for i:=2 to len do 95 begin 96 if(rank[sa[i]]<>rank[sa[i-1]])or(rank[sa[i]+j]<>rank[sa[i-1]+j])then 97 inc(m); 98 trank[sa[i]]:=m; 99 end; 100 j:=j*2;rank:=trank; 101 end; 102 end; 103 104 procedure geth; 105 var i,j,k:longint; 106 begin 107 k:=0; 108 for i:=1 to len do 109 begin 110 if rank[i]=1 then 111 begin 112 h[rank[i]]:=0;continue; 113 end; 114 j:=sa[rank[i]-1]; 115 while(s[i+k]=s[j+k])do inc(k); 116 h[rank[i]]:=k; 117 if k>0 then dec(k); 118 end; 119 end; 120 121 procedure getst; 122 var i,j,a,b:longint; 123 begin 124 mn[0]:=-1; 125 for i:=1 to len do 126 if i and(i-1)=0 then mn[i]:=mn[i-1]+1 else mn[i]:=mn[i-1]; 127 for i:=1 to len do st[0,i]:=h[i]; 128 for i:=1 to mn[len] do 129 for j:=1 to len+1-(1 shl i) do 130 st[i,j]:=min(st[i-1,j],st[i-1,j+(1 shl(i-1))]); 131 end; 132 133 function ask(a,b:longint):longint; 134 var d:longint; 135 begin 136 if a>b then swap(a,b); 137 d:=mn[b-a+1]; 138 exit(min(st[d,a],st[d,b-(1 shl d)+1])); 139 end; 140 141 procedure split(i,x:longint;var k1,k2:longint); 142 begin 143 if i=0 then 144 begin 145 k1:=0;k2:=0;exit; 146 end; 147 if t[i].w<x then 148 begin 149 k1:=i;split(t[i].r,x,t[i].r,k2); 150 end else 151 begin 152 k2:=i;split(t[i].l,x,k1,t[i].l); 153 end; 154 end; 155 156 function merge(x,y:longint):longint; 157 begin 158 if(x=0)and(y=0) then exit(x+y); 159 if t[x].f>t[y].f then 160 begin 161 t[x].r:=merge(t[x].r,y);exit(x); 162 end else 163 begin 164 t[y].l:=merge(x,t[y].l);exit(y); 165 end; 166 end; 167 168 begin 169 randomize; 170 readln(len); 171 for i:=1 to len do 172 begin 173 read(s[i]);op[i].id:=i;op[i].w:=s[i]; 174 end; 175 disc;for i:=1 to len div 2 do swap(s[i],s[len-i+1]); 176 getsa;geth; 177 getst; 178 root:=0; 179 for i:=len downto 1 do 180 begin 181 split(root,rank[i],k1,k2); 182 l:=k1;while t[l].r>0 do l:=t[l].r; 183 r:=k2;while t[r].l>0 do r:=t[r].l; 184 t[i].f:=random(maxlongint);t[i].w:=rank[i]; 185 root:=merge(merge(k1,i),k2); 186 tmp:=0; 187 if l>0 then tmp:=max(tmp,ask(rank[l]+1,rank[i])); 188 if r>0 then tmp:=max(tmp,ask(rank[i]+1,rank[r])); 189 now:=now+len-i+1-tmp; 190 writeln(now); 191 end; 192 end.
以上是关于bzoj4516: [Sdoi2016]生成魔咒的主要内容,如果未能解决你的问题,请参考以下文章