二、Sandy 的卡片
(card.pas/c/cpp, 限时1 秒,内存256M)
【题目描述】
Sandy 和Sue 的热衷于收集干脆面中的卡片。
然而,Sue 收集卡片是因为卡片上漂亮的人物形象,而Sandy 则是为了积攒卡片兑
换超炫的人物模型。
每一张卡片都由一些数字进行标记,第i 张卡片的序列长度为Mi,要想兑换人物模
型,首先必须要集够N 张卡片,对于这N 张卡片,如果他们都有一个相同的子串长度为
k,则可以兑换一个等级为k 的人物模型。相同的定义为:两个子串长度相同且一个串
的全部元素加上一个数就会变成另一个串。
Sandy 的卡片数远远小于要求的N,于是Sue 决定在Sandy 的生日将自己的卡片送给
Sandy,在Sue 的帮助下,Sandy 终于集够了N 张卡片,但是,Sandy 并不清楚他可以兑
换到哪个等级的人物模型,现在,请你帮助Sandy 和Sue,看看他们最高能够得到哪个
等级的人物模型。
【输入文件】
第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy 现在有的
卡片数
第i+1 行到第i+N 行每行第一个数为第i 张卡片序列的长度Mi,之后j+1 到j+1+Mi
个数,用空格分隔,分别表示序列中的第j 个数
【输出文件】
一个数k,表示可以获得的最高等级。
【样例】
输入样例:
2
2 1 2
3 4 5 9
输出样例:
2
【数据范围】
30%的数据保证n<=50
100%的数据保证n<=1000
100%的数据保证m[i]<=101
山东省选08年第二轮第一天试题
后缀数组求解
最小的当然是1了
将序列上两项之间的差为内容生成后缀数组
两个各不同序列之间用-maxlongint的来分隔
之后二分答案
按二分的答案将后缀分组
若一组中出现了所有的序列,则该答案成立
测试数据
http://mail.qq.com/cgi-bin/ftnExs_download?k=773535621076cf9e6412407d1a31044e000505520501014e1e530655565550020718540004041c550651054f540653041c070207055509540357055050313961525447061b4350133173&t=exs_ftn_download&code=155b511a
program card; var n,i,j,k,tot,m,max,all,s,e,mid,temp,last:longint; dl,root,belong:array [0..110001] of longint; change,total,rank,sa,now,keep,height:array [-1..110001] of longint; yes:array [0..1001] of boolean; xl:array [0..1001] of longint; ok:boolean; function search (mid:longint):boolean; begin if mid=0 then exit(true); fillchar(yes,sizeof(yes),false); k:=1; yes[belong[sa[n+1]]]:=true; all:=1; xl[1]:=belong[sa[n+1]]; for i:=n+2 to tot do begin if height[i]<mid then begin while all<>0 do begin yes[xl[all]]:=false; dec(all); end; all:=1; xl[1]:=belong[sa[i]]; yes[belong[sa[i]]]:=true; k:=1; continue; end; if not yes[belong[sa[i]]] then begin yes[belong[sa[i]]]:=true; inc(all); xl[all]:=belong[sa[i]]; inc(k); end; if k=n then exit(true); end; exit(false); end; procedure swap (var a,b:longint); var i:longint; begin i:=a; a:=b; b:=i; end; procedure qsort (s,e:longint); var i,j,k:longint; begin if s>=e then exit; i:=s; j:=e; k:=dl[(s+e) div 2]; while i<=j do begin while root[dl[i]]<root[k] do inc(i); while root[dl[j]]>root[k] do dec(j); if i>j then break; swap(dl[i],dl[j]); inc(i); dec(j); end; qsort(s,j); qsort(i,e); end; begin assign(input,'card.in'); reset(input); assign(output,'card.out'); rewrite(output); read(n); max:=maxlongint; tot:=0; for i:=1 to n do begin read(m); if m<max then max:=m; if m<>0 then read(last); for j:=tot + 1 to tot+m-1 do begin read(temp); root[j]:=temp-last; last:=temp; belong[j]:=i; end; tot:=tot+m; root[tot]:=-maxlongint; end; for i:=1 to tot do dl[i]:=i; qsort(1,tot); k:=1; for i:=1 to tot do begin if root[dl[i]]<>root[dl[k]] then k:=i; rank[dl[i]]:=k; end; k:=0; while 1 shl k<tot do begin for i:=1 to tot do if i+(1 shl k)>tot then change[i]:=0 else change[i]:=rank[i+(1 shl k)]; fillchar(total,sizeof(total),0); for i:=1 to tot do inc(total[change[i]]); for i:=1 to tot do total[i]:=total[i]+total[i-1]; for i:=1 to tot do begin inc(total[change[i]-1]); dl[total[change[i]-1]]:=i; end; fillchar(total,sizeof(total),0); ok:=true; for i:=1 to tot do begin inc(total[rank[i]]); if total[rank[i]]=2 then ok:=false; end; if ok then break; for i:=2 to tot do total[i]:=total[i]+total[i-1]; fillchar(now,sizeof(now),0); fillchar(keep,sizeof(keep),0); for i:=1 to tot do begin if now[rank[dl[i]]]<>change[dl[i]] then begin now[rank[dl[i]]]:=change[dl[i]]; total[rank[dl[i]]-1]:=total[rank[dl[i]]-1]+keep[rank[dl[i]]]; keep[rank[dl[i]]]:=0; end; inc(keep[rank[dl[i]]]); rank[dl[i]]:=total[rank[dl[i]]-1]+1; end; inc(k); end; for i:=1 to tot do sa[rank[i]]:=i; fillchar(height,sizeof(height),0); for i:=1 to tot do begin if rank[i]=1 then continue; k:=height[rank[i-1]]-1; if k<0 then k:=0; while (i+k<=tot)and(sa[rank[i]-1]+k<=tot) and(root[i+k]=root[sa[rank[i]-1]+k]) do inc(k); height[rank[i]]:=k; end; if max<=1 then begin writeln(max); close(input); close(output); exit; end; s:=1; e:=max; while s<>e do begin mid:=s+e-(s+e) div 2; if search(mid-1) then s:=mid else e:=mid-1; end; writeln(s); close(input); close(output); end.