Sdoi2008 Sandy的卡片
Description
Sandy和Sue的热衷于收集干脆面中的卡片。然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型。每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。Sandy的卡片数远远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到哪个等级的人物模型。
求出来的答案是相邻之差的最长公共序列长度啊
所以要加一啊加一
嘤嘤嘤
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 1000001
using namespace std;
int n,m=5500,px[M],sa[M],cnt[M],rnk[M],h[M],w,cn,minn=0x3f3f3f3f,f[M],b[5000],a[M],c[M],k;
void qsort()
{
for(int i=1;i<=m;i++) cnt[i]=0;
for(int i=1;i<=n;i++) cnt[rnk[i]]++;
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[ cnt[rnk[px[i]]]-- ]=px[i];
}
void SA()
{
for(int i=1;i<=n;i++) px[i]=i, rnk[i]=c[i];
qsort();
for(int w=1, p=0; p<n;m=p,w<<=1)
{
p=0;
for(int i=1;i<=w;i++) px[++p]=n+i-w;
for(int i=1;i<=n;i++) if(sa[i]>w) px[++p]=sa[i]-w;
qsort(); swap(px,rnk); rnk[sa[1]]=p=1;
for(int i=2;i<=n;i++) rnk[sa[i]]=(px[sa[i]]==px[sa[i-1]] && px[sa[i]+w]==px[sa[i-1]+w])? p:++p;
}
for(int i=1;i<=n;i++) if(rnk[i]>1)
{
int t=sa[rnk[i]-1], l=max(h[rnk[i-1]]-1,0);
while(c[i+l]==c[t+l]) l++;
h[rnk[i]]=l;
}
}
bool check(int x)
{
int c=1; memset(b,0,sizeof(b)); b[f[sa[1]]]=1;
for(int i=2;i<=n;i++)
{
if(h[i]<x) c=0, memset(b,0,sizeof(b));
if(!b[f[sa[i]]] && f[sa[i]]) c+=1, b[f[sa[i]]]=1;
if(c>=w) return 1;
}
return c>=w;
}
int ef(int l,int r)
{
int mid,tmp=l;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)) tmp=mid, l=mid+1;
else r=mid-1;
}
return tmp;
}
int main()
{
scanf("%d",&w);
for(int i=1;i<=w;i++)
{
scanf("%d",&k); minn=min(minn,k);
for(int j=1;j<=k;j++) scanf("%d",&a[++n]),f[n]=i;
a[++n]=2000+i;
}
for(int i=1;i<=n;i++)
{
c[i]=a[i]-a[i-1]+3000;
m=max(m,c[i]);
}
SA();
printf("%d",ef(0,minn)+1);
}