Sandy的卡片[SDOI2008]

                       题目传送门

 

题目描述

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,M<=1000,2<=Mi<=101

 

 题解:

  先对每个原串差分,再把n个差分后的串连在一起,中间用未出现过的字符隔开。求出height数组后进行二分答案,查看是否有满足条件的[l,r]使得区间内出现了n个卡组且height都大于等于二分出的x。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define LL long long
 6 #define RI register int
 7 using namespace std;
 8 const int INF = 0x7ffffff ;
 9 const int N = 1e6 + 1010 ;
10 
11 inline int read() {
12     int k = 0 , f = 1 ; char c = getchar() ;
13     for( ; !isdigit(c) ; c = getchar())
14       if(c == '-') f = -1 ;
15     for( ; isdigit(c) ; c = getchar())
16       k = k*10 + c-'0' ;
17     return k*f ;
18 }
19 int n, nn, k, p, q = 1, tot = 0, res = 0 ; int a[N], bl[N], sa[2][N], rk[2][N], h[N], v[N] ;
20 
21 inline void mul(int *sa,int *rk,int *SA,int *RK) {
22     for(int i=1;i<=n;i++) v[rk[sa[i]]] = i ;
23     for(int i=n;i;i--) if(sa[i] > k) SA[v[rk[sa[i]-k]]--] = sa[i]-k ;
24     for(int i=n-k+1;i<=n;i++) SA[v[rk[i]]--] = i ;
25     for(int i=1;i<=n;i++) RK[SA[i]] = RK[SA[i-1]] + (rk[SA[i]] != rk[SA[i-1]] || rk[SA[i]+k] != rk[SA[i-1]+k]) ;
26 }
27 inline void presa() {
28     for(int i=1;i<=n;i++) v[a[i]]++ ;
29     for(int i=1;i<=222;i++) v[i] += v[i-1] ;
30     for(int i=1;i<=n;i++) sa[p][v[a[i]]--] = i ;
31     for(int i=1;i<=n;i++) rk[p][sa[p][i]] = rk[p][sa[p][i-1]] + (a[sa[p][i]] != a[sa[p][i-1]]) ;
32     for(k=1;k<n;k<<=1,swap(p,q)) {
33         mul(sa[p],rk[p],sa[q],rk[q]) ;
34         if(rk[q][sa[q][n]] == n) {
35             swap(p,q) ; break ;
36         }
37     }
38     for(int i=1,k=0;i<=n;i++) {
39         int j = sa[p][rk[p][i]-1] ;
40         while(a[i+k] == a[j+k]) k++ ;
41         h[rk[p][i]] = k ; if(k) k-- ;
42     }
43 }
44 
45 int vv[1010] ;
46 inline void add(int x) {
47     if(!x) return ;
48     if(!vv[x]) res ++ ;
49     vv[x]++ ;
50 }
51 inline void del(int x) {
52     if(!x) return ;
53     vv[x]-- ;
54     if(!vv[x]) res -- ;
55 }
56 inline bool check(int x) {
57     memset(vv,0,sizeof(vv)) ;
58     int pre = 0 ; res = 0 ;
59     for(int i=1;i<=n;i++) {
60         if(h[i] < x) {
61             if(res == nn) return 1 ;
62             for(int j=pre+1;j<i;j++) del(bl[sa[p][j]]), del(bl[sa[p][j-1]]) ;
63             pre = i ;
64         }
65         else add(bl[sa[p][i]]), add(bl[sa[p][i-1]]) ;
66     }
67     if(res == nn) return 1 ;  // 刚刚那个提交少了这一行,其实是有漏洞的qaq 
68     return 0 ;
69 }
70 
71 int main() {
72     n = read() ;
73     for(int i=1;i<=n;i++) {
74         int mm = read() ; int now, pre = read() ;
75         for(int j=1;j<mm;j++) now = read(), a[++tot] = now-pre+102, pre = now, bl[tot] = i ;
76         if(i < n) a[++tot] = 222 ;
77     }
78     nn = n ; n = tot ; presa() ;
79     int L = 0, R = n, ans = 0 ;
80     while(L < R) {
81         int mid = (L+R)>>1 ;
82         if(check(mid)) ans = max(ans,mid), L = mid+1 ;
83         else R = mid ;
84     }
85 /*    
86     for(int i=1;i<=n;i++) printf("%d ",a[i]) ; printf("\n") ;    
87     for(int i=1;i<=n;i++) printf("%d ",h[rk[p][i]]) ; printf("\n") ;
88 */    
89     printf("%d",ans+1) ;
90     return 0 ;
91 }

  又一次把v[]开小了...不会再有下一次了qaq

转载于:https://www.cnblogs.com/zub23333/p/8760882.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值