码迷,mamicode.com
首页 > 其他好文 > 详细

[SDOI2008]Sandy的卡片

时间:2018-02-27 21:14:36      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:reg   namespace   get   radix   ++   top   分隔符   algorithm   rank   

题目描述

Sandy和Sue的热衷于收集干脆面中的卡片。

然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型。

每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。

Sandy的卡片数远远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到哪个等级的人物模型。

输入输出格式

输入格式:

第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy现在有的卡片数

第i+1行到第i+N行每行第一个数为第i张卡片序列的长度Mi,之后j+1到j+1+Mi个数,用空格分隔,分别表示序列中的第j个数

输出格式:

一个数k,表示可以获得的最高等级。

输入输出样例

输入样例#1: 复制
2
2 1 2
3 4 5 9
输出样例#1: 复制
2

说明

数据范围:

30%的数据保证n<=50

100%的数据保证n<=1000

因为是“相似”,所以把n个字符串差分

用不同且未出现的分隔符连起来

然后求后缀数组和LCP

二分答案k

把连续的h值不小于k的分为一组,如果一组内集齐了n个字符串的后缀

那么就可以构成长度为k的相似子串

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 int s[2000001],c[2000001],SA[2000001],h[2000001],n,m,x[2000001],y[2000001],rank[2000001],ans,tot,len[1501],cnt;
  8 int bel[2000001],mx=4000,a[2001][2001],top,st[2000001];
  9 bool vis[1501];
 10 void radix_sort()
 11 {int i;
 12   for (i=0;i<m;i++)
 13     c[i]=0;
 14   for (i=0;i<n;i++)
 15     c[x[y[i]]]++;
 16   for (i=1;i<m;i++)
 17     c[i]+=c[i-1];
 18   for (i=n-1;i>=0;i--)
 19     SA[--c[x[y[i]]]]=y[i];
 20 }
 21 void build_SA()
 22 {int i,j,k,p;
 23   for (i=0;i<n;i++)
 24     x[i]=s[i],y[i]=i;
 25   m=1000000;
 26   radix_sort();
 27   for (k=1;k<=n;k<<=1)
 28     {
 29       p=0;
 30       for (i=n-k;i<n;i++)
 31     y[p++]=i;
 32       for (i=0;i<n;i++)
 33     if (SA[i]>=k) y[p++]=SA[i]-k;
 34       radix_sort();
 35       p=1;swap(x,y);
 36       x[SA[0]]=0;
 37       for (i=1;i<n;i++)
 38     x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&((SA[i]+k<n?y[SA[i]+k]:-1)==(SA[i-1]+k<n?y[SA[i-1]+k]:-1)))?p-1:p++;
 39       if (p>=n) break;
 40       m=p;
 41     }
 42   for (i=0;i<n;i++)
 43     rank[SA[i]]=i;
 44   int L=0;
 45   for (i=0;i<n;i++)
 46     if (rank[i]>0)
 47       {
 48     if (L>0) L--;
 49     j=SA[rank[i]-1];
 50     while (i+L<n&&j+L<n&&(s[j+L]==s[i+L])) L++;
 51     h[rank[i]]=L;
 52       }
 53 }
 54 bool check(int mid)
 55 {
 56   int num=0;
 57   for(int i=0;i<=n;i++)
 58     {
 59       if(h[i]<mid)
 60     {
 61       num=0;
 62       while(top) vis[st[top--]]=0;
 63     }
 64       if(!vis[bel[SA[i]]])
 65     {
 66       vis[bel[SA[i]]]=1;
 67       num++;
 68       st[++top]=bel[SA[i]];
 69     }
 70       if(num==tot)return 1;
 71     }    
 72   return 0;
 73 }
 74 int main()
 75 {int l,r,i,now,last,j;
 76   cin>>tot;r=2e9;
 77   for (i=1;i<=tot;i++)
 78     {
 79       scanf("%d",&len[i]);
 80       r=min(r,len[i]);
 81       for (j=1;j<=len[i];j++)
 82     {
 83       scanf("%d",&a[i][j]);
 84     }
 85     }
 86   for (i=1;i<=tot;i++)
 87     {
 88       for (j=2;j<=len[i];j++)
 89     {
 90       s[cnt]=a[i][j]-a[i][j-1]+2000;
 91       bel[cnt]=i;
 92       cnt++;
 93     }
 94       s[cnt++]=++mx;
 95     }
 96   n=cnt;
 97   build_SA();
 98   l=1;r--;
 99   ans=0;
100   while (l<=r)
101     {
102       int mid=(l+r)/2;
103       if (check(mid)) ans=mid,l=mid+1;
104       else r=mid-1;
105     }
106   cout<<ans+1;
107 }

 

[SDOI2008]Sandy的卡片

标签:reg   namespace   get   radix   ++   top   分隔符   algorithm   rank   

原文地址:https://www.cnblogs.com/Y-E-T-I/p/8480466.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!