BZOJ 4698: Sdoi2008 Sandy的卡片

时间:2023-03-09 19:12:19
BZOJ 4698: Sdoi2008 Sandy的卡片

4698: Sdoi2008 Sandy的卡片

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 106  Solved: 40
[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

Sample Output

2

HINT

Source

[Submit][Status][Discuss]

首先,对于题目中的匹配,可以转换成两个相邻数字之间差值的匹配问题。因此对于每个数字串,先前后做差得到新的数字串,然后把N个新串连起来求后缀数组。二分答案,在后缀数组中找出所有联系的height值>=k的区间,判断是否能满足存在N个在不同串中开始的后缀,如果能,就是一个合法的k。

调了好久都不对,满脸黑线,一怒之下打开Vim,参考hzwer的代码,没加tab就一A了。

 #include <bits/stdc++.h>
using namespace std;
#define N 1005
#define M 1000005
int n,mn=2e9,mx=,lt,rt=2e9,mid,ans=;
int a[N][N],l[N],b[M],id[M],tot,vis[N],cnt;
int sa[M],ta[M],rk[M],ht[M],wa[M],wb[M],ca[M],cb[M];
inline bool check(int k)
{
  for(int i=;i<=tot;++i)
  {
    if(ht[i]<k)memset(vis,,sizeof(vis)),cnt=;
    if(!vis[id[sa[i]]])vis[id[sa[i]]]=,++cnt;
    if(cnt==n)return true;
  }
  return false;
}
signed main(void)
{
  scanf("%d",&n);
  for(int i=;i<=n;++i)
  {
    scanf("%d",l+i);
    for(int j=;j<=l[i];++j)
    {
      scanf("%d",&a[i][j]);
      if(j>)mx=max(mx,a[i][j]-a[i][j-]);
    }
    rt=min(rt,l[i]);
  }
  for(int i=;i<=n;++i)
  {
    for(int j=;j<=l[i];++j)b[++tot]=a[i][j]-a[i][j-],id[tot]=i;
    b[++tot]=++mx;
  }
  for(int i=;i<=tot;++i)mn=min(mn,b[i]);
  for(int i=;i<=tot;++i)b[i]=b[i]-mn+,mx=max(mx,b[i]);
  memset(ca,,sizeof(ca));
  for(int i=;i<=tot;++i)++ca[b[i]];
  for(int i=;i<=mx;++i)ca[i]+=ca[i-];
  for(int i=tot;i>=;--i)sa[ca[b[i]]--]=i;
  rk[sa[]]=;
  for(int i=;i<=tot;++i)rk[sa[i]]=rk[sa[i-]]+(b[sa[i]]!=b[sa[i-]]);
  for(int k=;rk[sa[tot]]<tot;k<<=)
  {
    memset(ca,,sizeof(ca));
    memset(cb,,sizeof(cb));
    for(int i=;i<=tot;++i)++ca[wa[i]=rk[i]],++cb[wb[i]=i+k<=tot?rk[i+k]:];
    for(int i=;i<=tot;++i)ca[i]+=ca[i-],cb[i]+=cb[i-];
    for(int i=tot;i>=;--i)ta[cb[wb[i]]--]=i;
    for(int i=tot;i>=;--i)sa[ca[wa[ta[i]]]--]=ta[i];
    rk[sa[]]=;
    for(int i=;i<=tot;++i)rk[sa[i]]=rk[sa[i-]]+(wa[sa[i]]!=wa[sa[i-]]||wb[sa[i]]!=wb[sa[i-]]);
  }
  for(int i=,j=;i<=tot;++i)
  {
    if(--j<)j=;
    while(b[i+j]==b[sa[rk[i]-]+j])++j;
    ht[rk[i]]=j;
  }
  while(lt<=rt)
  {
    if(check(mid=(lt+rt)>>))
      ans=mid+,lt=mid+;
    else rt=mid-;
  }
  printf("%d\n",ans);
}

2017.01.13 补加Tab

@Author: YouSiki