[Sdoi2008]Sandy的卡片

Posted Mafia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Sdoi2008]Sandy的卡片相关的知识,希望对你有一定的参考价值。

[Sdoi2008]Sandy的卡片

题目

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

OUTPUT

2

解题报告

这道题其实挺简单= =,就是个处理多字符串最长公共字串= =

主要的是如何处理出加上某个数相等的字串

我们想,既然这个串中的每个数加上某个数能变成另一个串,那么该串中的各个数的差一定对应相等

那么我们就对差值建$SA$,跑最长公共字串,把$ans$加一即可

技术分享
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 inline int read(){
 6     int sum(0),f(1);
 7     char ch(getchar());
 8     for(;ch<0||ch>9;ch=getchar())
 9         if(ch==-)
10             f=-1;
11     for(;ch>=0&&ch<=9;sum=sum*10+(ch^48),ch=getchar());
12     return sum*f;
13 }
14 int T;
15 int len[1005],xl[1005][1005];
16 int s[105000],bl[105000],cnt;
17 int n,m;
18 int t1[105000],t2[105000],t3[105000],buc[105000];
19 int sa[105000],rank[105000],height[105000];
20 inline void Suffix(){
21     int i,j,k(0),p(0),*x(t1),*y(t2),*t;
22     for(i=0;i<=m;++i)buc[i]=0;
23     for(i=1;i<=n;++i)++buc[x[i]=s[i]];
24     for(i=1;i<=m;++i)buc[i]+=buc[i-1];
25     for(i=n;i>=1;--i)sa[buc[x[i]]--]=i;
26     for(j=1;p<n;j<<=1,m=p){
27         for(p=0,i=n-j+1;i<=n;++i)y[++p]=i;
28         for(i=1;i<=n;++i)
29             if(sa[i]>j)
30                 y[++p]=sa[i]-j;
31         for(i=0;i<=m;++i)buc[i]=0;
32         for(i=1;i<=n;++i)t3[i]=x[y[i]];
33         for(i=1;i<=n;++i)++buc[t3[i]];
34         for(i=1;i<=m;++i)buc[i]+=buc[i-1];
35         for(i=n;i>=1;--i)sa[buc[t3[i]]--]=y[i];
36         for(t=x,x=y,y=t,x[sa[1]]=1,p=1,i=2;i<=n;++i)
37             x[sa[i]]=((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+j]==y[sa[i-1]+j]))?p:++p;
38     }
39     for(i=1;i<=n;++i)rank[sa[i]]=i;
40     for(i=1;i<=n;height[rank[i++]]=k)
41         for(k?k--:0,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
42 }
43 int l(0),r(0x7fffffff),mid,ans(0);
44 bool flag[1005];
45 inline bool check(int x){
46     int i,j,k;
47     for(i=1;i<=n;++i){
48         if(height[i]>=x){
49             for(j=i;j<=n&&height[j]>=x;++j);
50             --j;
51             memset(flag,0,sizeof(flag));
52             for(k=i-1;k<=j;++k)
53                 flag[bl[sa[k]]]=1;
54             for(k=1;k<=T&&flag[k];++k);
55             if(k==T+1)
56                 return true;
57             i=j;
58         }
59     }
60     return false;
61 }
62 int main(){
63     T=read();
64     for(int i=1;i<=T;++i){
65         len[i]=read();
66         r=min(r,len[i]);
67         for(int j=1;j<=len[i];++j){
68             xl[i][j]=read();
69             if(j!=1)
70                 m=max(xl[i][j]-xl[i][j-1],m);
71         }
72     }
73     for(int i=1;i<=T;++i){
74         for(int j=2;j<=len[i];++j){
75             s[++cnt]=xl[i][j]-xl[i][j-1];
76             bl[cnt]=i;
77         }
78         s[++cnt]=++m;
79     }
80     n=cnt;
81     Suffix();
82     while(l<=r){
83         mid=(l+r)>>1;
84         if(check(mid))
85             ans=mid,l=mid+1;
86         else
87             r=mid-1;
88     }
89     printf("%d",ans+1);
90 }
View Code

 

以上是关于[Sdoi2008]Sandy的卡片的主要内容,如果未能解决你的问题,请参考以下文章

[SDOI2008]Sandy的卡片

SDOI2008Sandy的卡片

[SDOI2008]Sandy的卡片

4698. [SDOI2008]Sandy的卡片后缀数组

BZOJ 4698: Sdoi2008 Sandy的卡片

bzoj4698 / P2463 [SDOI2008]Sandy的卡片