# 洛谷P2463 [SDOI2008]Sandy的卡片(后缀数组SA + 差分 + 二分答案)

【题意】

【思路】

【check方法】

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 5;
int n, t, M, b[maxn], num[110], a[maxn];
int sa[maxn], x[maxn], c[maxn], y[maxn], rk[maxn], height[maxn];
bool vis[maxn];
inline void get_sa(){
int m = 2000;
for( int i=1; i<=n; i++ ) ++c[x[i]=a[i]];
for( int i=1; i<=m; i++ ) c[i] += c[i-1];
for( int i=n; i; i-- ) sa[c[x[i]]--] = i;
for( int k=1; k<=n; k<<=1 ){
int now = 0;
for( int i=n-k+1; i<=n; i++ ) y[++now] = i;
for( int i=1; i<=n; i++ ) if(sa[i]>k) y[++now] = sa[i]-k;
for( int i=0; i<=m; i++ ) c[i] = 0;
for( int i=1; i<=n; i++ ) ++c[x[i]];
for( int i=1; i<=m; i++ ) c[i] += c[i-1];
for( int i=n; i; i-- ) sa[c[x[y[i]]]--] = y[i], y[i]=0;
swap(x, y);
x[sa[1]] = now = 1;
for( int i=2; i<=n; i++ )
x[sa[i]] = (y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? now : ++now;
if( now>=n ) return ;
m = now;
}
}

inline void get_height(){
int k = 0;
for( int i=1; i<=n; i++ ) rk[sa[i]] = i;
for( int i=1; i<=n; i++ ){
if( rk[i]==1 ) continue;
if( k ) k--;
int j = sa[rk[i]-1];
while( j+k<=n && i+k<=n && a[j+k]==a[i+k] ) k++;
height[rk[i]] = k;
}
}

inline bool check1( int l, int r ){
if( r-l+1<t ) return 0;                 //!!!!!!!r-l+1<t  不是r-l+1<n
int tmp = 0;
memset( vis, 0, sizeof(vis) );
for( int i=l; i<=r; i++ )
if( !vis[b[sa[i]]] ){
tmp ++;
vis[b[sa[i]]] = 1;
}
return tmp == t;
}

inline bool check( int x ){
int l=1, r=1;
while( l<=n ){
while( height[r+1]>=x ) r++;
if( check1(l, r) ) return 1;
l = r+1; r = l;
}
return 0;
}

int main(){
freopen("in.txt", "r", stdin);
scanf("%d", &t);
int len = 0;
for( int i=1; i<=t; i++ ){
scanf("%d", &M);
for( int j=0; j<M; j++ ) scanf("%d", &num[j]);
for( int j=1; j<M; j++ ){
a[++n] = num[j]-num[j-1];           //进行差分
b[n] = i;
}
a[++n] = 0;         //分隔不同的串
b[n] = i;
}
// for( int i=1; i<=n; i++ ) cout << a[i] << endl;
get_sa();
get_height();
// for( int i=1; i<=n; i++ ) cout << height[i] <<endl;
int l=1, r=n;
int ans=0;
while( l<=r ){
int mid = l+r>>1;
if( check(mid) ) ans = mid, l=mid+1;
else r = mid-1;
}
printf("%d\n", ans+1);

return 0;
}

posted @ 2019-09-21 15:29  CoffeeCati  阅读(193)  评论(0编辑  收藏  举报