BZOJ 4698: Sdoi2008 Sandy的卡片
Posted NeighThorn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 4698: Sdoi2008 Sandy的卡片相关的知识,希望对你有一定的参考价值。
4698: Sdoi2008 Sandy的卡片
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 225 Solved: 95
[Submit][Status][Discuss]
Description
Sandy和Sue的热衷于收集干脆面中的卡片。然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积
攒卡片兑换超炫的人物模型。每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型
,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人
物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。Sandy的卡片数远
远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片
,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到
哪个等级的人物模型。
Input
第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy现在有的卡片数
第i+1行到第i+N行每行第一个数为第i张卡片序列的长度Mi,之后j+1到j+1+Mi个数,用空格分隔,分别表示序列中
的第j个数
n<=1000,M<=1000,2<=Mi<=101
Output
一个数k,表示可以获得的最高等级。
Sample Input
2
2 1 2
3 4 5 9
2 1 2
3 4 5 9
Sample Output
2
HINT
Source
分析:
深夜写模板题...听起来不错...
把$n$个串连起来求一个后缀数组,然后二分答案$k$,判断是否存在一个连续的$height>=k$区间出现了$n$个串...
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=1000+5,maxm=1000+5,maxlen=2000000+5; int n,m,Min,s[maxlen],id[maxlen],len[maxn],vis[maxn],str[maxn][maxm]; int sa[maxlen],gs[maxlen],wb[maxlen],wv[maxlen],ran[maxlen],height[maxlen]; inline bool cmp(int *x,int a,int b,int l){ return x[a]==x[b]&&x[a+l]==x[b+l]; } inline void da(int *sa,int *x,int n,int m){ int i,j,p,*y=wb; for(i=0;i<m;i++) gs[i]=0; for(i=0;i<n;i++) gs[x[i]]++; for(i=1;i<m;i++) gs[i]+=gs[i-1]; for(i=n-1;~i;i--) sa[--gs[x[i]]]=i; for(j=1,p=1;p<n;j<<=1,m=p){ for(i=n-j,p=0;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;i++) gs[i]=0; for(i=0;i<n;i++) gs[wv[i]]++; for(i=1;i<m;i++) gs[i]+=gs[i-1]; for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i]; p=1;swap(x,y);x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++; } } inline void calcheight(int n){ int i,j,k=0; for(i=0;i<=n;i++) ran[sa[i]]=i; for(i=0;i<n;height[ran[i++]]=k) for(k?k--:233,j=sa[ran[i]-1];s[j+k]==s[i+k];k++); } inline bool check(int k){ int cnt=0; for(int l=1,r;l<=n;l=r+1){ while(l<n&&height[l]<k) l++; r=l;if(r==n&&height[r]<k) return false; while(r<n&&height[r+1]>=k) r++; if(r-l+2>=m){ memset(vis,0,sizeof(vis));cnt=0; for(int i=l-1;i<=r;i++) if(id[sa[i]]) cnt+=vis[id[sa[i]]]^1,vis[id[sa[i]]]=1; if(cnt==m) return true; } } return false; } signed main(void){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif scanf("%d",&m);Min=1000; for(int i=1;i<=m;i++){ scanf("%d",&len[i]),Min=min(Min,len[i]); for(int j=1;j<=len[i];j++) scanf("%d",&str[i][j]); } n=0; for(int i=1;i<=m;i++,ran[n]=s[n++]=2000+i) for(int j=2;j<=len[i];j++) id[n]=i,ran[n]=s[n++]=str[i][j]-str[i][j-1]; da(sa,ran,n+1,4000);calcheight(n); int l=1,r=Min-1,ans=0; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans+1); return 0; }
By NeighThorn
以上是关于BZOJ 4698: Sdoi2008 Sandy的卡片的主要内容,如果未能解决你的问题,请参考以下文章
bzoj4698 / P2463 [SDOI2008]Sandy的卡片