題目描述
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,表示可以獲得的最高等級。
?
輸入輸出樣例
2 2 1 2 3 4 5 9
2
說明
數據范圍:
30%的數據保證n<=50
100%的數據保證n<=1000,M<=1000,2<=Mi<=101
?
題意:
給定幾串序列,問他們最長公共子序列是多長。
思路:
類似之前做的Muisical, Themehttps://www.cnblogs.com/wyboooo/p/9865919.html
都是可以通過增加一個定值,所以只需要處理間隔。
不同的地方在于這個題目是多個不同的串。可以想到的是,是不是可以將這些串拼接起來。
拼起來就需要考慮一個問題,找到的這個串應該要避免他們跨越了拼接的那個間隔。
所以首先我們應該要用一個原來的串中從來沒有出現過的字符來分隔兩個串。
其次,當我們二分尋找答案的時候,應該要考慮我們找到的這個區間,他們表示的后綴的首字母也就是sa[i],是不是分別屬于n個串。
所以我們要標好每個位置屬于哪個串。
1 #include <iostream> 2 #include <set> 3 #include <cmath> 4 #include <stdio.h> 5 #include <cstring> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 using namespace std; 11 typedef long long LL; 12 #define inf 0x7f7f7f7f 13 14 const int maxn = 1005; 15 int a[maxn][maxn], s[maxn * maxn], s_len[maxn], id[maxn * maxn], vis[maxn]; 16 int sa[maxn * maxn]; 17 int t1[maxn * maxn], t2[maxn * maxn], c[maxn * maxn]; 18 int rnk[maxn * maxn], height[maxn * maxn]; 19 int n, len; 20 21 void build_sa(int s[], int n, int m) 22 { 23 int i, j, p, *x = t1, *y = t2; 24 for(i = 0; i < m; i++)c[i] = 0; 25 for(i = 0; i < n; i++)c[x[i] = s[i]]++; 26 for(i = 1; i < m; i++)c[i] += c[i - 1]; 27 for(i = n - 1; i >= 0; i--)sa[--c[x[i]]] = i; 28 for(j = 1; j <= n; j <<= 1){ 29 p = 0; 30 for(i = n - j; i < n; i++)y[p++] = i; 31 for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j; 32 for(i = 0; i < m; i++)c[i] = 0; 33 for(i = 0; i < n; i++)c[x[y[i]]]++; 34 for(i = 1; i < m; i++)c[i] += c[i - 1]; 35 for(i = n - 1; i >= 0; i--)sa[--c[x[y[i]]]] = y[i]; 36 swap(x, y); 37 p = 1; 38 x[sa[0]] = 0; 39 for(i = 1; i < n; i++){ 40 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p - 1 : p++; 41 } 42 if(p >= n)break; 43 m = p; 44 } 45 } 46 47 void get_height(int s[], int n) 48 { 49 int i, j, k = 0; 50 for(i = 0; i <= n; i++)rnk[sa[i]] = i; 51 for(i = 1; i <= n; i++){ 52 if(k)k--; 53 j = sa[rnk[i] - 1]; 54 while(s[i + k] == s[j + k])k++; 55 height[rnk[i]] = k; 56 } 57 } 58 int sta[maxn * maxn], top; 59 bool check(int mid) 60 { 61 while(top)vis[sta[top--]] = false; 62 for(int i = 1; i <= len; i++){ 63 if(height[i] < mid){ 64 while(top)vis[sta[top--]] = false; 65 } 66 if(!vis[id[sa[i]]]){ 67 vis[id[sa[i]]] = true; 68 sta[++top] = id[sa[i]]; 69 if(top == n)return true; 70 } 71 } 72 return false; 73 } 74 75 int main() 76 { 77 scanf("%d", &n); 78 len = 0; 79 int mmx = -1; 80 for(int i = 1; i <= n; i++){ 81 vis[i] = false; 82 scanf("%d", &s_len[i]); 83 for(int j = 1; j <= s_len[i]; j++){ 84 scanf("%d", &a[i][j]); 85 if(j)mmx = max(mmx, a[i][j] - a[i][j - 1]); 86 } 87 } 88 int mmin = inf; 89 for(int i = 1; i <= n; i++){ 90 for(int j = 2; j <= s_len[i]; j++){ 91 s[++len] = a[i][j] - a[i][j - 1]; 92 id[len] = i; 93 mmin = min(mmin, s[len]); 94 } 95 s[++len] = ++mmx; 96 } 97 for(int i = 1; i <= len; i++){ 98 s[i] = s[i] - mmin + 1; 99 //cout<<s[i]<<endl; 100 } 101 102 build_sa(s, len + 1, 2000); 103 /*for(int i = 1; i <= len; i++){ 104 cout<<sa[i]<<endl; 105 }*/ 106 get_height(s, len); 107 /*cout<<len<<endl; 108 for(int i = 2; i <= len; i++){ 109 cout<<height[i]<<endl; 110 }*/ 111 //cout<<len<<endl; 112 int st = 0, ed = len, ans = -1; 113 while(st <= ed){ 114 int mid = (st + ed) / 2; 115 if(check(mid)){ 116 st = mid + 1; 117 ans = mid; 118 } 119 else{ 120 ed = mid - 1; 121 } 122 } 123 124 printf("%d\n", ans + 1); 125 return 0; 126 }
?