• 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了。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define N 1005
     4 #define M 1000005
     5 int n,mn=2e9,mx=0,lt,rt=2e9,mid,ans=1;
     6 int a[N][N],l[N],b[M],id[M],tot,vis[N],cnt;
     7 int sa[M],ta[M],rk[M],ht[M],wa[M],wb[M],ca[M],cb[M];
     8 inline bool check(int k)
     9 {
    10   for(int i=1;i<=tot;++i)
    11   {
    12     if(ht[i]<k)memset(vis,0,sizeof(vis)),cnt=0;
    13     if(!vis[id[sa[i]]])vis[id[sa[i]]]=1,++cnt;
    14     if(cnt==n)return true;
    15   }
    16   return false;
    17 }
    18 signed main(void)
    19 {
    20   scanf("%d",&n);
    21   for(int i=1;i<=n;++i)
    22   {
    23     scanf("%d",l+i);
    24     for(int j=1;j<=l[i];++j)
    25     {
    26       scanf("%d",&a[i][j]);
    27       if(j>1)mx=max(mx,a[i][j]-a[i][j-1]);
    28     }
    29     rt=min(rt,l[i]);
    30   }
    31   for(int i=1;i<=n;++i)
    32   {
    33     for(int j=2;j<=l[i];++j)b[++tot]=a[i][j]-a[i][j-1],id[tot]=i;
    34     b[++tot]=++mx;
    35   }
    36   for(int i=1;i<=tot;++i)mn=min(mn,b[i]);
    37   for(int i=1;i<=tot;++i)b[i]=b[i]-mn+1,mx=max(mx,b[i]);
    38   memset(ca,0,sizeof(ca));
    39   for(int i=1;i<=tot;++i)++ca[b[i]];
    40   for(int i=1;i<=mx;++i)ca[i]+=ca[i-1];
    41   for(int i=tot;i>=1;--i)sa[ca[b[i]]--]=i;
    42   rk[sa[1]]=1;
    43   for(int i=2;i<=tot;++i)rk[sa[i]]=rk[sa[i-1]]+(b[sa[i]]!=b[sa[i-1]]);
    44   for(int k=1;rk[sa[tot]]<tot;k<<=1)
    45   {
    46     memset(ca,0,sizeof(ca));
    47     memset(cb,0,sizeof(cb));
    48     for(int i=1;i<=tot;++i)++ca[wa[i]=rk[i]],++cb[wb[i]=i+k<=tot?rk[i+k]:0];
    49     for(int i=1;i<=tot;++i)ca[i]+=ca[i-1],cb[i]+=cb[i-1];
    50     for(int i=tot;i>=1;--i)ta[cb[wb[i]]--]=i;
    51     for(int i=tot;i>=1;--i)sa[ca[wa[ta[i]]]--]=ta[i];
    52     rk[sa[1]]=1;
    53     for(int i=2;i<=tot;++i)rk[sa[i]]=rk[sa[i-1]]+(wa[sa[i]]!=wa[sa[i-1]]||wb[sa[i]]!=wb[sa[i-1]]);
    54   }
    55   for(int i=1,j=0;i<=tot;++i)
    56   {
    57     if(--j<0)j=0;
    58     while(b[i+j]==b[sa[rk[i]-1]+j])++j;
    59     ht[rk[i]]=j;
    60   }
    61   while(lt<=rt)
    62   {
    63     if(check(mid=(lt+rt)>>1))
    64       ans=mid+1,lt=mid+1;
    65     else rt=mid-1;
    66   }
    67   printf("%d
    ",ans);
    68 }

    2017.01.13 补加Tab

    @Author: YouSiki

  • 相关阅读:
    mysql 45讲 索引的使用 09-11
    mysql 45讲 相关锁的概念 06-08
    mysql 45讲 深入浅出索引04-05
    mysql 45讲 概览 01-03
    AQS源码解析第二回
    面试相关-怎么实现限流功能
    人工智能必备数学基础:线性代数基础(2)
    Elasticsearch问题总结和解决方法
    spring boot中打印所有日志
    Java中Stream流里面的findFirst()和findAny()区别
  • 原文地址:https://www.cnblogs.com/yousiki/p/6210982.html
Copyright © 2020-2023  润新知